🍱 Lunchbox Hands

accessibility

WCAG Contrast Ratio Explained: What 4.5:1 Actually Means

How contrast ratio is calculated, the real rules behind WCAG AA and AAA, when 3:1 is enough, and the mistakes that make accessible-looking designs fail — with a free checker.

Every accessibility audit flags it, every design system claims it, and almost nobody can say what it actually measures: contrast ratio. The number — “4.5:1”, “3:1”, “7:1” — comes from a specific formula in the WCAG spec, and once you understand it, the rules stop feeling arbitrary. Here’s what the ratio really is, which threshold applies where, and the traps that make designs fail audits despite “looking fine.”

What the ratio actually measures

Contrast ratio compares the relative luminance of two colors — roughly, how bright each one appears to the human eye. The formula is:

(L1 + 0.05) / (L2 + 0.05)

where L1 is the lighter color’s luminance and L2 the darker’s. Luminance itself is computed from the RGB channels, weighted for how sensitive our eyes are to each: green counts most, blue least. The + 0.05 accounts for ambient light reflecting off a screen — it’s why the scale runs from 1:1 (identical colors) to 21:1 (pure black on pure white), not to infinity.

Two consequences fall out of the math:

  • Hue barely matters; lightness is everything. Pure red (#ff0000) on pure blue (#0000ff) screams visually but scores only about 2.1:1 — a hard fail. Contrast ratio measures brightness difference, not color difference.
  • The scale is not linear. Getting from 3:1 to 4.5:1 usually requires a bigger color change than it sounds. Darkening a mid-gray by “one shade” often isn’t enough.

The thresholds: AA, AAA, and large text

WCAG defines two conformance levels that matter in practice:

ContentAA (the standard)AAA (enhanced)
Normal body text4.5:17:1
Large text (≥24px, or ≥18.66px bold)3:14.5:1
UI components & graphical objects3:1
Disabled controls, decorative text, logosexemptexempt

AA is the level laws and contracts reference — the ADA (via DOJ rulemaking), Section 508, and the European Accessibility Act all point at WCAG AA. AAA is aspirational for body text but a good target for long-form reading surfaces.

The large-text exception trips people up in both directions. The spec’s actual units are points: 18pt (24 CSS px) regular, or 14pt (~18.66 CSS px) bold. An 18px heading is not large text — it needs the full 4.5:1.

The rule everyone forgets: 3:1 for UI components

Since WCAG 2.1, non-text contrast (success criterion 1.4.11) requires 3:1 for the parts of an interface you need to perceive to use it: input borders, checkbox outlines, focus indicators, icon buttons, chart lines. The classic failure is the fashionable light-gray input border — #e0e0e0 on white is about 1.3:1, invisible to plenty of users. Placeholder text styled at #aaa (2.3:1) fails the text rule too, and it’s the default look of half the web.

Common ways “it looks fine” fails the math

  • Gray on white. #999999 on white is 2.8:1 — fail. You need roughly #767676 (4.54:1) or darker for body text. This single fact fixes most audits.
  • White text on brand colors. White on a bright brand orange or medium green frequently lands between 2:1 and 3:1. Test the real hex, not the vibe. Often the fix is darkening the background a step, not changing the text.
  • Text over images and gradients. The ratio must hold at the worst point behind the text. A scrim or solid text plate is the reliable fix.
  • Dark mode flips your failures. A palette audited on white doesn’t inherit its passes on #121212. Audit both themes; the pairs that fail are usually different ones.
  • Thin fonts. A 300-weight font at 4.6:1 reads worse than a 400-weight at 4.5:1. The formula doesn’t know about stroke width — treat borderline passes with thin type as failures in spirit.

Passing contrast isn’t the whole job

Contrast ratio measures legibility — whether text is readable at all. It says nothing about whether two colors are distinguishable from each other, which is what fails for the ~8% of men with color vision deficiency. A red error state and green success state can each pass 4.5:1 against white and still be identical to a deuteranope. They’re different bugs with different tools: check legibility with the Contrast Checker, then check distinguishability with the Color Blindness Simulator — the “designing for color blindness” guide covers that half in depth.

Check your palette in 30 seconds

The free Contrast Checker runs entirely in your browser: paste foreground and background hex values and you get the exact ratio plus pass/fail against every AA and AAA threshold, for normal and large text. Working from a design token file? Convert between hex, RGB, and HSL with the Color Converter, and build compliant combinations from the start with the Color Palette Generator.

The whole discipline compresses to one habit: check the pair, not the palette. Colors aren’t accessible or inaccessible on their own — only combinations are. Every text-on-background pair your UI actually renders is a number, and the number either clears the bar or it doesn’t.