fix(cli): contrast audit reads an element's own opaque background#1975
Draft
miguel-heygen wants to merge 1 commit into
Draft
fix(cli): contrast audit reads an element's own opaque background#1975miguel-heygen wants to merge 1 commit into
miguel-heygen wants to merge 1 commit into
Conversation
The WCAG contrast audit estimated each text element's background by sampling a 4px pixel ring just OUTSIDE its bounding box. For an element that paints its OWN opaque background (a caption pill, a CTA button, a solid card), the text is composited over that solid color, not over whatever surrounds the box. Sampling the ring there measured the text against the scene behind the element (often a dark photo), producing false ~1:1 ratios and flagging perfectly readable CTAs and captions. Users reported the warning persisting no matter how they changed the background color, because the audit was never reading it. Resolve the nearest fully-opaque background-color by walking the element up its ancestor chain, and use it when present; keep sampling the ring only when the text sits over image pixels (a background-image is hit first) or no opaque background exists. The pure decision lives in a new commands/contrast-bg.ts with unit tests; contrast-audit.browser.js (injected as a raw string, so it cannot import) inlines the same logic, mirroring the existing duplicated-WCAG-math note.
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.
Problem
hyperframes validate's WCAG contrast audit estimates each text element's background by sampling a 4px pixel ring just outside its bounding box (contrast-audit.browser.js). For an element that paints its own opaque background (a caption pill, a CTA button, a solid card), the text is composited over that solid color, not over whatever surrounds the box. Sampling the ring there measures the text against the scene behind the element (often a dark photo), producing false ~1:1 ratios and flagging perfectly readable CTAs/captions.The tell users kept hitting: changing the element's background color never moved the reported ratio (only changing the text color did) — because the audit was never reading the background it complained about.
Fix
Resolve the nearest fully-opaque background-color by walking the element up its ancestor chain, and use it as the background when present. Keep sampling the pixel ring only when the text genuinely sits over image pixels (a
background-imageis encountered first) or no opaque background-color exists. A semi-transparent background-color is skipped (it blends with what's below, which the ring captures better).The pure decision lives in a new
packages/cli/src/commands/contrast-bg.tswith unit tests.contrast-audit.browser.jsis injected into the page as a raw string (it cannotimport), so it inlines the same logic — mirroring the existing "WCAG math is duplicated, keep in sync" note already at the top of that file.Verification
packages/cli/src/commands/contrast-bg.test.ts— 8 assertions covering: own opaque bg used; transparent element → opaque ancestor used;background-imagefirst → defer to ring (null); semi-transparent skipped; nothing opaque → null. All pass. Existing over-image behavior is unchanged (null path → same ring sampling as before).