Addaly is in open beta. Things will change, and AI answers can be wrong — check anything that matters.

Design, Before Any Software

Hierarchy, type, colour and spacing — the part of design you can do with a pencil, before any software.

Lesson 37 of 749 min

What a contrast checker is actually computing

The number, and where it comes from

Every contrast checker you have used reports a ratio between 1:1 and 21:1. Here is the whole computation, so it stops being magic.

Step one: linearise each channel. Screen values are gamma-encoded, so 128 is not half the light of 255. Convert each of R, G and B from 0-255 to 0-1, then:

c_lin = c / 12.92                     if c ≤ 0.03928
c_lin = ((c + 0.055) / 1.055) ^ 2.4   otherwise

Step two: weight and sum, using the sensitivity weights from the previous lesson:

L = 0.2126·R_lin + 0.7152·G_lin + 0.0722·B_lin

Step three: take the ratio, with a constant added to both sides:

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

Black against white gives (1 + 0.05) / (0 + 0.05) = 21. That is the maximum, and it is why no checker ever reports more.

The 0.05 is not decoration. It models ambient light reflecting off the screen — flare — which never lets a real black be truly black in a real room. Without it, black on black would compute as an infinite ratio.

The thresholds

The Web Content Accessibility Guidelines set these, and they are the numbers that appear in law in many countries:

  • 1.4.3 Contrast (Minimum), level AA — 4.5:1 for normal text, 3:1 for large text.
  • 1.4.6 Contrast (Enhanced), level AAA — 7:1 normal, 4.5:1 large.
  • 1.4.11 Non-text Contrast, level AA — 3:1 for user interface components and meaningful graphics: a button's border, a form field's outline, an icon carrying information, the bars of a chart.

Large text has a precise definition: at least 18 point, or 14 point bold. In CSS pixels at the usual 96dpi assumption, that is 24px, or 18.66px bold. Not 18px. The three-quarters of a pixel matters if you are claiming conformance.

Two numbers worth memorising because they come up constantly:

What a contrast checker is computingLineariseUndo the gammaencoding on eachchannelWeight and sumGreen 0.7152, red0.2126, blue 0.0722Take the ratioAdding 0.05 to both,for screen flareCompare4.5 to 1 body text, 3to 1 large textThe flare constant models ambient light bouncing off the glass. It is why black on black computes as 1to 1 rather than infinite, and why the scale stops at 21 to 1.
What a contrast checker is computingLineariseUndo the gamma encoding on each channelWeight and sumGreen 0.7152, red 0.2126, blue 0.0722Take the ratioAdding 0.05 to both, for screen flareCompare4.5 to 1 body text, 3 to 1 large textThe flare constant models ambient light bouncing offthe glass. It is why black on black computes as 1 to1 rather than infinite, and why the scale stops at21 to 1.
  • #767676 on white is 4.54:1 — the lightest neutral grey that passes AA for body text on a white background.
  • #949494 on white is 3:1 — the lightest that passes for large text and for interface components.

Any grey lighter than #767676 for body text on white fails, whatever it looks like on your monitor.

Where to check, free

  • WebAIM Contrast Checker in a browser, which also tells you which criteria pass.
  • Chrome and Firefox developer tools: open the colour picker on any text element and the ratio is displayed, with a line on the picker showing where the passing region begins.
  • Firefox's Accessibility inspector will audit a whole page for contrast issues in one pass.
  • Chrome's Lighthouse audit reports failures across a page, and runs from the same panel.

None of this requires a paid tool or a plugin.

Two traps

Opacity. Text at rgba(0,0,0,0.6) has no contrast ratio of its own; it depends entirely on what is behind it. Change the background from white to a pale grey card and the ratio drops without anything in the text changing. Checkers cannot evaluate semi-transparent text without knowing the composite, and many people check the declared colour rather than the rendered one. Compute the blended value, or set solid colours.

Text over images. There is no single ratio, because the background varies across the image. The criterion still applies, and the usual solutions are a solid scrim behind the text, a gradient overlay, or placing the text in a plain region. Check the worst pixel, not the average.

Working the formula once, by hand

Do it once and you will never be mystified by a checker again. Take mid-grey #808080 on white.

Each channel is 128/255 = 0.502. That is above 0.03928, so linearise with the power form:

((0.502 + 0.055) / 1.055) ^ 2.4
= (0.528) ^ 2.4
= 0.2158

All three channels are equal, so the weights sum to 1 and the luminance is 0.2158. White has a luminance of 1. The ratio is therefore

(1 + 0.05) / (0.2158 + 0.05) = 1.05 / 0.2658 = 3.95

So #808080 on white is about 3.95:1 — it passes for large text and fails for body text, which surprises almost everybody the first time. The grey that looks like a perfectly reasonable secondary text colour is not one.

Notice what the power of 2.4 does: it pushes mid-range values down hard. A colour that is numerically halfway between black and white carries only about a fifth of white's light. That single non-linearity is why intuition about contrast is unreliable and why the check is worth running rather than estimating.

What passing does and does not mean

Passing 4.5:1 is a floor for a conformance requirement, not a claim that the text is comfortable. A 12px light-weight face at exactly 4.5:1 satisfies the criterion and is genuinely hard to read; a 17px semibold at 7:1 is easy. The criterion cannot see the difference, and the next lesson is about exactly that gap.

For most interface text the practical target is comfortably above the minimum — 7:1 or better for body text costs you nothing and removes an entire class of complaint.

The one thing to keep

A contrast ratio is the linearised, sensitivity-weighted luminance of two colours compared with a flare constant added to both, capped at 21:1 — and the 4.5:1 threshold is a conformance floor rather than a guarantee that text is comfortable to read.

Before you move on

A team checks its body text colour of rgba(0,0,0,0.62) against a white page background, gets 5.7:1, and ships. Users on the settings page, where content sits on pale grey cards, report the text is hard to read. What went wrong?

Pick the one you would defend. Nobody sees your answer.

No ads. No data sale. No public scores on people. Ever.

© 2026 Addaly