The numbers
The ratio is computed from the relative luminance of the two colours: identical colours are 1:1, black on white is 21:1. On a white background, #767676 is exactly 4.54:1 — the lightest grey that passes for body text, and a number worth memorising.
| What | AA | AAA |
|---|---|---|
| Body text | 4.5:1 | 7:1 |
| Large text — 24px, or 18.66px bold | 3:1 | 4.5:1 |
| The visual boundary of a control, and meaningful graphics | 3:1 | — |
| Disabled controls, logos, purely decorative things | no requirement | — |
So is a disabled-looking label that is not actually disabled, so is a "subtle" caption, and so is white text on a brand colour. The two that fail in almost every design system are placeholder grey and a mid-tone brand colour used for links.
Contrast is not only text
The boundary that tells you where a control is, the focus ring, the bars in a chart, an icon that carries meaning: all 3:1. A form whose fields are outlined in #eee is a form that some people cannot find.
input { border: 1px solid #ddd; } /* 1.3:1 against white — the field is invisible */
input { border: 1px solid #767676; } /* 4.5:1 — comfortably past the 3:1 needed */
:focus-visible { outline: 2px solid #00eadc; } /* must reach 3:1 against what is behind it */
Never colour alone
This is a separate criterion from contrast and it is the one that catches required fields marked only in red, links inside text that are only a different colour, chart series distinguished only by hue, and error states shown only by a red border.
Underlining links inside body text is the classic fix. If the design refuses, they need at least 3:1 against the surrounding text and a non-colour indicator on hover and focus.
<!-- invisible to 8% of men, and to anyone on a bad screen -->
<span style="color: red">Out of stock</span>
<!-- colour, plus a word, plus a shape -->
<span class="stock stock--out">✕ Out of stock</span>
<!-- and in a chart: different dash patterns or markers, not only different colours -->
Designing with it rather than auditing for it
- Pick text colours from a small scale where every combination is already checked, and put the ratio in the token name if it helps:
--text-mutedis a decision, not a hex code somebody picked. - Check the dark theme separately — a palette that passes on white often fails on graphite, and vice versa.
- Check the hover and disabled states, the focus ring, and text over images (an overlay or a gradient scrim is the usual answer).
- Test with the browser's contrast tool in the inspector; it shows the ratio live as you change the colour.