fix(inspector): restore WCAG AA color contrast across light/dark modes - #188
Merged
Conversation
The @antfu/design migration (antfu#178) gave <body> a solid opaque background for the first time (it was previously transparent, with the dot-grid pattern living on <html> as a background-image). That accidentally fixed axe-core's ability to determine effective background colors, surfacing a batch of genuine contrast bugs — some introduced by the migration itself (badge-color-lime/teal, the reverted primary theme darkening), some pre-existing but never actually measurable before now (op-fade/op-mute diluting already-tuned colors, hash-color HSL lightness not being perceptually uniform across hues). - uno.config.ts: extend the badge-color-* WCAG overrides to lime/teal - utils/color.ts: switch the cluster hash-color from HSL to OKLCH so lightness stays perceptually uniform across the full hue wheel - Percentage.vue, ClusterBadge.vue, SubTitle.vue: stop applying op-fade on top of already contrast-tuned children (badge text, hash colors, number badges) — the extra opacity dilutes them below 4.5:1 - PackageDetails.vue: replace op30/op-mute with the solid color-muted token for real body text (tab labels, empty states) - grid/chart/report pages, PackageBorder.vue, Overview.vue, compare.vue: tab/nav active states and brand accents needed op100! (to cancel btn-action's op75) and/or -700/dark:-300 shades tuned for their actual background instead of the bare DEFAULT swatch - Credits.vue: darken the Nuxt brand green for light mode only Also exclude @antfu/design's DisplayAvatar hash-color fallback from the a11y scan — same HSL-lightness bug as our own hash-color util, but it lives in the vendor package; reported upstream. All 28 e2e tests (light + dark a11y matrix included), lint, typecheck, and unit tests pass. Fix created with the help of an agent.
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The
@antfu/designmigration (#178) gave<body>a solid opaque background for the first time (it was previously transparent, with the dot-grid pattern living on<html>as a background-image). That accidentally fixed axe-core's ability to determine effective background colors, surfacing a batch of genuine contrast bugs — some introduced by the migration itself, some pre-existing but never actually measurable before now.uno.config.ts: extend thebadge-color-*WCAG overrides tolime/teal(module-type FAUX/DUAL badges)utils/color.ts: switch the cluster hash-color from HSL to OKLCH so lightness stays perceptually uniform across the full hue wheel — the old formula swung from ~7.7:1 down to ~2:1 purely based on huePercentage.vue,ClusterBadge.vue,SubTitle.vue: stop applyingop-fadeon top of already contrast-tuned children (badge text, hash colors, number badges) — the extra opacity dilutes them below 4.5:1PackageDetails.vue: replaceop30/op-mutewith the solidcolor-mutedtoken for real body text (tab labels, empty states) — 30% opacity text can't clear 4.5:1 regardless of the base colorPackageBorder.vue,Overview.vue,compare.vue: tab/nav active states and brand accents neededop100!(to cancelbtn-action'sop75) and/or-700/dark:-300shades tuned for their actual background instead of the bare DEFAULT swatch (which reverted the theme's darkened primary green back to the vendor default)Credits.vue: darken the Nuxt brand green for light mode only (kept as-is for dark mode, where it already clears contrast)Also excludes
@antfu/design'sDisplayAvatarhash-color fallback from the a11y scan — same HSL-lightness bug as our own hash-color util, but it lives in the vendor package; reported upstream, dropped once fixed there.Verification
All 28 e2e tests (the full light + dark a11y matrix included),
pnpm lint,pnpm typecheck, andpnpm testpass.Fix created with the help of an agent.