How WCAG Contrast Ratios Actually Work
Accessibility guidance for text is unusually concrete: it gives you a number. Normal text needs a contrast ratio of at least 4.5:1 against its background to meet WCAG AA, large text needs 3:1, and AAA raises those to 7:1 and 4.5:1. What is less widely understood is where that ratio comes from — and why two color pairs with the same ratio can feel very different to read.
The number is a ratio of relative luminance
Contrast ratio is defined as (L1 + 0.05) / (L2 + 0.05), where L1 and L2 are the relative luminances of the lighter and darker color. Relative luminance is not simply the average of the RGB channels: each channel is first linearised (undoing the sRGB gamma curve) and then weighted — roughly 21% red, 72% green, 7% blue — because the human eye is far more sensitive to green light than to blue.
That weighting has a practical consequence people find surprising: pure blue text on black is nearly unreadable and scores terribly, while pure yellow on black scores extremely well, even though both are "one bright primary-ish color on black". Green does most of the work of making something look bright.
The + 0.05 in both terms represents ambient light reflecting off the screen. It is why the scale tops out at 21:1 (pure white on pure black) rather than running to infinity.
Why large text gets an easier target
The thresholds are about legibility, not about color as such, and a thicker letterform is easier to resolve at low contrast than a thin one. WCAG defines "large" as at least 18pt (24px), or 14pt (18.66px) if bold. Below that, you are on the 4.5:1 line. This is the rule most often applied incorrectly — a 20px light-weight heading is large text; a 16px bold label is not.
The gap between passing and readable
A ratio is a floor, not a verdict. Several things pass 4.5:1 and are still hard to read:
- Thin weights. The formula knows nothing about stroke width. A 300-weight font at 4.6:1 will be meaningfully harder to read than a 500-weight font at the same ratio.
- Text over images or gradients. The ratio is computed against one background color. If the background varies, the worst case is what matters, not the average.
- Large areas of saturated color. Two strongly saturated colors can hit a high ratio and still vibrate uncomfortably against each other.
- Non-text elements. Icons, focus rings and input borders have their own 3:1 requirement under WCAG 2.1, and these are the things most often forgotten.
Checking it
The contrast checker computes the ratio for any foreground/background pair and shows all four thresholds at once, so you can see not just whether it passes but by how much. It also gives you a link to the exact pair, which is the fastest way to settle a disagreement in a code review — send the link rather than the screenshot.
If a pair fails, the usual fix is lightness rather than hue: keep the color, move it toward or away from the background in the L channel. The color picker makes that a one-slider change.