Accessibility

WCAG contrast ratio explained: what 4.5:1 actually measures

Everyone quotes the number. Far fewer people know it comes from a formula with a fudge factor in it, why the fudge factor is there, and where the formula quietly fails.

The requirement is familiar: body text needs a contrast ratio of at least 4.5:1 against its background. Large text needs 3:1. Interface components need 3:1. Most people stop there, paste two colors into a contrast checker, and move on.

It is worth knowing what the checker is doing, because the WCAG contrast ratio formula has known blind spots and you will eventually hit one.

The contrast ratio formula

Contrast ratio is defined as:

(L1 + 0.05) / (L2 + 0.05)

where L1 is the relative luminance of the lighter color and L2 the darker. Relative luminance is not the L from HSL. It is computed by taking each sRGB channel, undoing the display gamma curve, and weighting the results:

L = 0.2126 R + 0.7152 G + 0.0722 B

Those weights are the whole story of why green feels bright and blue does not. Green carries over 70% of perceived luminance; blue carries barely 7%. Pure blue #0000FF on black scores 2.44:1. Pure yellow #FFFF00 on black scores 19.56:1. Both are fully saturated primaries at maximum intensity. The eye simply is not built symmetrically.

What the 0.05 is doing

That constant is a flare allowance. It models the light bouncing off your screen from the room you are sitting in. Without it, black on black would divide by zero and every pair of very dark colors would return an absurdly high ratio.

With it, the ratio tops out at exactly 21:1 for black on white, and the darkest pairs get pulled towards a realistic number rather than a theoretical one. It is a fudge factor, but a principled one.

WCAG contrast requirements, and what they exempt

Level Applies to Needs
AA Normal text 4.5:1
AA Large text (24px, or 18.66px bold) 3:1
AA UI components, graphical objects 3:1
AAA Normal text 7:1
AAA Large text 4.5:1

The exemptions catch people out. Under WCAG 2.2, no contrast requirement applies to:

  • Logotypes and brand names as part of a logo.
  • Text that is purely decorative.
  • Text in an inactive or disabled control.
  • Text that is part of a photograph containing significant other visual content.

That last one is narrower than people assume. Text laid over a photo is not exempt. It still has to pass against whatever is behind it, which usually means a scrim or a solid plate.

Where the formula fails

The WCAG 2 ratio is symmetric. Swap the two colors and the number does not change. Human vision is not symmetric. Light text on a dark background blooms: the letters appear to thin out and the gaps inside them fill in. A pair that reads comfortably as dark text on a light background can be noticeably worse reversed, and the ratio will report both as identical.

It is also blind to size and weight. The standard handles this with a single crude step at the “large text” boundary, but the real relationship is continuous: a 14px light weight and a 14px bold have meaningfully different contrast needs, and both count as “normal text”.

This is what APCA, the Accessible Perceptual Contrast Algorithm being developed for WCAG 3, is designed to fix. It reports a signed Lc value from roughly −108 to 106, where the sign encodes polarity and the magnitude maps onto specific size and weight recommendations. Lc 75 is the practical floor for body copy.

Which one do you have to meet?

WCAG 2.2 is the one written into procurement rules, the European Accessibility Act and Section 508. Conform to it. Use APCA as a second opinion: it catches pairs that scrape past 4.5:1 and still read badly, and it is far more useful for dark mode.

Three traps in real projects

Opacity. A color at 60% opacity is blended with whatever is behind it. The effective contrast is against the blend, not the nominal value. Flatten it first, then test.

Placeholder text. Almost always fails. It is real text conveying real information and it gets no exemption for being gray.

Focus indicators. They need 3:1 against the adjacent background under the focus appearance criteria in WCAG 2.2. A pale ring on a pale background is one of the most common failures in otherwise careful work.

Testing without losing your brand

When a pair fails, the instinct is to reach for black. You rarely need to. Contrast is almost entirely a lightness relationship, so you can hold hue and chroma constant and move lightness alone until the pair clears. The color still reads as your color; it is just a step darker or lighter.

That is exactly what the color contrast checker does when a pair fails: it walks the OKLCH lightness axis in small steps and reports the nearest passing value in both directions. Usually the fix is smaller than you expect.

Read next