Skip to main content

Command Palette

Search for a command to run...

My contrast check found nothing, so I broke it on purpose

An accessibility pass on my company site: a measuring tool that read every colour as black, the sanity check that caught it, and what was actually wrong

Updated
•4 min read•View as Markdown
My contrast check found nothing, so I broke it on purpose
B
Founder of Narcoleptic Fox. Marine veteran. Senior engineer learning AI/ML and writing about it. Building Mousing.ai, Reqforay,.ai, and foxstash.

An AI review of my company's website said some secondary text "appears small or muted" and suggested raising contrast. Fair enough. Muted grey on near-black is a classic accessibility failure, and the fix sounds simple: brighten the grey.

But brightening a colour token changes every page at once, and the colours come from a design system with rules of its own. So before touching a token I wanted a number: which text, on which background, fails which standard.

Claude Code, my pair on this, wrote the measurement. The first one was useless.

Every colour was black

The first pass walked every text element on eight pages, worked out its colour and the colour behind it, and computed the WCAG contrast ratio. The standard wants at least 4.5:1 for body text and 3:1 for large text.

The results came back looking like a disaster. Ratios of 1.00, 1.01, 1.03. White buttons on white. Text invisible against its own background.

They weren't. The site defines its colours in oklch(), a modern CSS colour format. The measurement converted colours by painting them onto a canvas and reading the pixel back, and the canvas didn't accept oklch(). Every colour it couldn't parse silently stayed black. So it was comparing black with black, everywhere, and reporting it as fact.

What kept that from turning into a redesign was that the numbers were too absurd to believe, and the rule that came out of it: before trusting a converter, run it on pairs whose answers are already known. White on black must be 21:1. Black on black must be 1:1. #767676 on white is about 4.54:1. The canvas converter would have failed the first one.

Measuring again

The rebuilt converter asks the browser itself to translate each colour into sRGB, then does the contrast arithmetic. It got the three known pairs exactly: 21, 1 and 4.54.

The real result: zero failures. Every text element on all eight pages meets WCAG AA. The "muted" grey is 7.63:1 on the page background and 6.91:1 on cards. That's well past 4.5:1, and on the background it even clears the stricter AAA level.

A check that finds nothing has to prove it can find something

Zero is the number I'd most want to hear and the one I trust least. A checker that is subtly broken (wrong selector, wrong background, an early return) also reports zero.

So we planted failures: a dark grey paragraph on the page background, and translucent white text on the teal band. The checker flagged both, at 1.75:1 and 2.70:1. Only then did the zero mean anything.

What was actually wrong

If contrast was fine, why did the text read as muted? Size. Counting text under 13 pixels on the home page found 19 blocks. Most were uppercase eyebrow labels, small by design and left alone. The rest were captions and chips inside the product illustrations, at 12 pixels. Those went to 13.

The other note in the review was "lengthy opening copy". Counted, most page openings ran 28 to 79 words. One product page ran 107 across four paragraphs. It's now 86 across three. The detail it dropped is still on the page, further down, where someone who wants it will look.

No colour token changed.

If you're buying software

When someone tells you a check passed, ask what it would have looked like if it had failed, and whether anyone has seen it fail. The broken version of this measurement didn't report "unknown". It reported, confidently, that every colour on the site was black. A tool that can't fail on purpose can't be trusted when it passes.