Every accessibility checklist tells you text needs a contrast ratio of 4.5:1. Far fewer explain what that number is, why the scale runs from 1:1 to 21:1, or why two colors that look “pretty different” can still fail. This guide covers the mechanics in plain language.
The ratio compares luminance, not color
A contrast ratio has nothing to do with hue. Red versus green, blue versus orange — the formula never sees “color” at all. It compares the relative luminance of two colors: a number between 0 (pure black) and 1 (pure white) describing how bright a color appears to the human eye, with each RGB channel weighted by how sensitive we are to it (green counts the most, blue the least).
The formula itself is short:
contrast = (L1 + 0.05) / (L2 + 0.05)where L1 is the lighter color’s luminance and L2 the darker one’s. Because the lighter value is always on top, the order of the two colors doesn’t matter: white on navy and navy on white are the same 16:1 ratio. The 0.05 terms model ambient light reflecting off a screen, and they’re why the scale tops out at 21:1 — pure black on pure white — instead of infinity.
What the numbers feel like
#C7C7C7text#FFFFFFbackground#949494text#FFFFFFbackground#767676text#FFFFFFbackground#595959text#FFFFFFbackgroundFour grays on white, sitting exactly at the common thresholds.
The scale is closer to logarithmic than linear in how it feels: the jump from 1.5:1 to 3:1 is dramatic, while 15:1 versus 21:1 is barely noticeable. That’s why the standards concentrate their thresholds at the low end, where legibility is actually won or lost.
The thresholds that matter
| Content | WCAG AA | WCAG AAA |
|---|---|---|
| Normal text (under 24px) | 4.5:1 | 7:1 |
| Large text (24px+, or 18.66px bold) | 3:1 | 4.5:1 |
| UI elements — icons, borders, focus rings | 3:1 | — |
If you want the reasoning behind choosing AA or AAA, that’s its own topic — see WCAG AA vs AAA.
Where designs fail even when the math passes
- Opacity. Text at 60% opacity doesn’t have the color you picked — it has a blend of your color and whatever is behind it. Always measure the rendered color.
- Thin fonts. The ratio assumes reasonably solid strokes. A 100-weight font at 4.5:1 reads worse than a 400-weight font at the same ratio; the standard doesn’t capture that, so treat thin faces as needing extra margin.
- Gradients and images. A gradient background has a different ratio at every point. Your text only needs to fail at one of them — see readable text over gradients.
- Placeholder and disabled text. Placeholder text is real content people must read; it needs the same 4.5:1. (Genuinely disabled controls are exempt.)
Try it in the tool
Check any pair in one click: the PaletteSense contrast checker gives you the ratio plus every AA/AAA verdict at once, and can test text over gradients. Programmatic? The same math is a free JSON API.
One number, honestly earned
A contrast ratio is a blunt instrument — it knows nothing about font weight, motion, or glare. But it’s objective, reproducible, and catches the failure that locks the most people out: text that low vision simply cannot resolve. Get every pair to its threshold first; polish from there.