What WCAG contrast ratios actually mean.

A "4.5:1" pass tells you a design clears a bar — but the number isn't the difference between two colors, and it isn't symmetric in the way you'd expect. Here's what the ratio actually computes, why a yellow-on-white that looks fine can fail, and what the AA and AAA thresholds are really protecting.

You ship a design, run a contrast checker, and it says 4.51 : 1 — passes AA. Nudge the text one shade lighter and it drops to 4.42 : 1 — fails. A single hex digit flipped the verdict. To know whether that line is meaningful or arbitrary, you have to know what the checker is computing — and it's stranger, and more principled, than "how different are these two colors."

The short version: contrast ratio is not a subtraction of two colors. It's a ratio of their relative luminance — a model of how much light each color sends to your eye — and it's deliberately weighted so that the channels the human eye cares most about count most. Understanding those two facts explains every surprising result a contrast checker ever gives you.

Why it's a ratio, not a difference.

The intuitive model of contrast is "how far apart are these colors" — some distance in RGB space, or a difference in lightness. WCAG explicitly does not do that. It defines contrast as a ratio of two luminance values:

contrast = (L_lighter + 0.05) / (L_darker + 0.05)

where L is the relative luminance of each color, a number from 0 (black) to 1 (white). Because it's a ratio of the lighter to the darker, the result runs from 1:1 (two identical colors) up to 21:1 (pure black against pure white). And because you always divide the larger by the smaller, order doesn't matter: black text on white and white text on black have the exact same ratio. Swapping foreground and background never changes the number.

A ratio is the right shape because perception of brightness is roughly multiplicative, not additive. The jump from a luminance of 0.01 to 0.02 is far more visible than 0.50 to 0.51, even though the absolute difference is identical. Dividing rather than subtracting captures that: the same ratio means roughly the same perceived separation whether you're in the dark end or the light end of the scale.

Relative luminance: why green outweighs blue.

The luminance of a color is not its raw RGB value, and computing it takes two steps that are easy to skip and wrong to skip.

Step one: undo gamma. The R, G, B values in a hex color aren't linear measures of light — they're gamma-encoded, so that 8-bit values spend more precision in the dark tones where the eye is sensitive. To get physical light you first divide each channel by 255, then linearize it:

c_linear = c ≤ 0.03928
  ? c / 12.92
  : ((c + 0.055) / 1.055) ^ 2.4

Step two: weight by the eye's sensitivity. The linear channels are then combined with very unequal coefficients:

L = 0.2126·R + 0.7152·G + 0.0722·B

Green carries roughly 71% of perceived luminance; red about 21%; blue barely 7%. This is physiology, not preference — the human retina has far more receptors tuned to green wavelengths than to blue. The practical consequence surprises people: #0000FF blue on black is a brutal, low-contrast combination (blue contributes almost no luminance, so the ratio is tiny), while #00FF00 green on black is blindingly high-contrast. Two colors that feel "equally saturated" can sit at wildly different luminances.

The mental model: luminance answers "how much light does this color throw," and the eye measures that light mostly in green. Contrast is then how many times more light the brighter color throws than the darker one.

The formula, and the mysterious +0.05.

That + 0.05 added to both luminances looks like a fudge factor. It's doing real work. Without it, any color against pure black (L = 0) would divide by zero and give an infinite ratio. The 0.05 models a small amount of ambient light reflecting off a real screen — no display is ever truly, perfectly black in a real room. It caps the maximum ratio at a sane 21:1 (that's (1 + 0.05) / (0 + 0.05)) and keeps the math well-behaved at the dark end.

It also means the dark end is where small color changes swing the ratio most. Near black, the denominator is dominated by that 0.05, so a tiny change in a dark color's luminance moves the ratio sharply — which is exactly why dark-theme text colors are so finicky to tune, and why your checker can flip from pass to fail on one hex digit when both colors are dark.

The thresholds: AA, AAA, large, UI.

WCAG 2.1 sets different floors depending on what the color pair is used for. The two that dominate are normal text and large text; the third, for interface components, is newer and widely missed.

TargetAAAAA
Normal text (under ~18.66px, or under 24px)4.5 : 17 : 1
Large text (≥ 24px, or ≥ 18.66px bold)3 : 14.5 : 1
UI components & meaningful graphics3 : 1

Why large text gets a lower bar. Bigger glyphs have thicker strokes and more area, so they stay legible at lower contrast. "Large" has a precise definition: at least 24px (18pt), or at least 18.66px (14pt) if bold. Note that AAA for large text (4.5:1) is the same number as AA for normal text — a useful coincidence to remember.

The component rule everyone forgets. WCAG 1.4.11 (added in 2.1) requires 3:1 contrast for non-text things that carry meaning: the border of a text input, a toggle's on/off states, focus rings, icons that convey information, the slices of a chart. A page can have perfect text contrast and still fail because its form fields are outlined in a whisper-grey that disappears against the background. The contrast checker's "UI & graphics" line is checking exactly this floor.

Where the ratio misleads you.

The number is a floor, not a guarantee of good design. Three things it can't see:

It's luminance-only, so it ignores hue clashes. Two colors can pass 4.5:1 and still be painful — saturated complementary hues at similar lightness (red on blue, say) can vibrate uncomfortably even with a passing ratio. The math measures light, not the chromatic aberration your eye does at color boundaries.

It says nothing about color being your only signal. A red "error" and a green "success" can both have gorgeous contrast against the background and still be invisible to a red-green colorblind user, because the only thing distinguishing them is hue. Contrast ratio and color-independence are separate requirements (WCAG 1.4.1 covers the latter); passing one tells you nothing about the other.

It assumes solid colors. Text over a photograph, a gradient, or a semi-transparent overlay has a different ratio at every pixel. A single foreground/background check can only approximate that — you have to test against the worst-case region behind the text, not an average.

None of this makes the ratio less useful. It makes it a fast, objective floor: clear it everywhere first, then use judgement for the things the number can't measure.

Takeaways.

The thing to remember: contrast ratio is a ratio of relative luminance (1:1 to 21:1), weighted heavily toward green, order-independent, and floored at the dark end by a 0.05 ambient-light term. Hit 4.5:1 for body text, 3:1 for large text and UI components, and treat the number as a floor you clear before — not instead of — checking hue and color-independence.

The reason one hex digit can flip "pass" to "fail" isn't that the standard is arbitrary. It's that you were standing exactly on a threshold, in the dark region where the ratio moves fastest. Once you can see the luminance machinery underneath the number, the verdict stops being a mystery and starts being a dial you know how to turn.

Check any color pair in your browser.

The Contrast Checker computes the exact ratio with the official relative-luminance formula and shows AA/AAA pass-fail for normal text, large text, and UI components — live, as you pick colors. Nothing is uploaded; it all runs in your tab. Use it to find the lightest text shade that still clears the bar.

Open the Contrast Checker
Tooly mascot

Made with love by a very serious person pretending not to be. Tooly McToolface is a workshop of free, client-side web tools. If the luminance-and-perception framing landed, what CSS color-scheme actually controls takes the same "what's really happening" lens to dark mode, and the Contrast Checker and Color Grabber are the matching tools.