The other day a client sent me a screenshot of his site open on his phone, out in the street, with a short message: "I can't read anything." I opened it, stared, and he was dead right. That gorgeous light-gray over white that looked so elegant on my calibrated monitor, indoors, simply vanished in the sun. And look, I could have pretended it was his phone's fault. But the truth is more uncomfortable: the mistake was mine, and I'd made it before.
It took me a while to internalize something I now find obvious: contrast isn't a matter of taste, it's math. There's a formula, it has a name (WCAG), and it couldn't care less how sophisticated you think that gray looks. The text either passes or it doesn't. Let me tell you how I got here — and at the end there's a live checker so you can watch the math happen.
The gorgeous light-gray nobody reads
There's a very common aesthetic vice among people who like "clean" design: lowering the text's opacity. That #999 over white, or an opacity: 0.6 on a whole paragraph, gives a sense of lightness, of breathing room, of something expensive. The problem is that this lightness is a privilege — of whoever is looking at a good screen, in a controlled environment, with perfect vision.
Take that same text out of the lab: put it under the sun, on a cheap low-brightness screen, or in front of someone who is 50 with the famous "tired eyes" (presbyopia), or color-blind, or low-vision. Suddenly that elegant gray turns into an unreadable haze. And here's the number that scared me: roughly 1 in 12 men has some color-vision deficiency. It's not a rare corner case — it's a huge slice of your visitors.
The big insight: our eyes don't see "brightness" fairly
Here's the part that rewired my brain. When the browser shows the color #2563eb (my brand blue), it's mixing three channels: red, green and blue. But our eye does not weigh those three equally. We're far more sensitive to green, reasonably sensitive to red, and quite insensitive to blue.
That's why a yellow (full of green and red) looks luminous, while a pure blue, even a "vibrant" one, looks dark to us. WCAG captures this in a formula called relative luminance: it takes the RGB, "undoes" the gamma adjustment screens apply, and then does a weighted average — ~21% red, ~72% green, ~7% blue. Notice that green alone dominates nearly three quarters of perceived brightness.
With both colors' luminance in hand, the contrast ratio is just a division:
(L_light + 0.05) / (L_dark + 0.05). The result ranges from 1:1 (same color, invisible) to 21:1 (pure black on pure white). That 0.05 is a trick to simulate the ambient light that always hits a screen — without it, black on black would divide by zero.
The numbers that count as law
WCAG turns that ratio into concrete targets. You don't have to memorize the formula, but the thresholds are worth keeping:
- 4.5:1 — the minimum for normal text to pass level AA. It's the ruler most accessibility laws around the world use as reference.
- 3:1 — enough for large text (from ~24px, or ~18.7px if bold). Bigger letters forgive lower contrast.
- 7:1 — level AAA for normal text, the gold standard. 4.5:1 already clears AAA for large text.
The beautiful detail: these are objective rules. No more arguing about "but it looks nice this way." The math either hits 4.5 or it doesn't. That freed me from a lot of unproductive fights — with clients and with myself.
Two curiosities I carry with me
- Color alone is never information. That classic "fields in red are required" excludes anyone who can't tell red from green. The golden rule: color can reinforce, but the information must also live in text, an icon, or a shape. Red + an "x" + the word "error." Never color alone.
- Contrast doesn't see hue, only brightness. This surprises everyone: a red and a green that seem to fight your eyes can have nearly the same luminance — and therefore terrible contrast against each other, even though they're "opposite" colors. That's why trusting your eyes deceives you; the math doesn't.
My honest take, after getting it wrong
Today I treat contrast the way I treat security: not a "nice extra" bolted on at the end, but a prerequisite that travels alongside the color choices. Accessibility and aesthetics are not enemies — that's the lazy excuse. You can have a beautiful, sophisticated site and have it readable in the sun. It just takes more thought from the start than slapping on a light gray and moving on.
And there's the side I care about most, as someone who builds things to convert: text nobody reads sells nothing. The most beautiful CTA in the world, if it disappears into the background, is money thrown away. Legibility is, above all, respect for the visitor — and respect converts.
Enough theory — play with the math 👇
I built a live contrast checker, vanilla, with no libraries at all. Pick the text color and the background (with the pickers or by typing the hex), and watch the contrast ratio computed live, with the AA and AAA badges lighting up green or red. Drag the luminance controls to feel how green weighs more than blue, and use the "suggest accessible color" button when your pair fails. It's the WCAG formula running right in front of you.