( Design )
Colour contrast: what WCAG actually requires
What contrast ratio does WCAG require?
At Level AA: 4.5:1 for normal text and 3:1 for large text. Level AAA raises those to 7:1 and 4.5:1, which is worth knowing about but is not what regulations and buyers ask for.
The ratio is a number between 1:1 (identical colours, invisible) and 21:1 (pure black on pure white). It is calculated from the relative luminance of the two colours, which is why a mid-grey on white and a mid-grey on black can produce very different results despite feeling similarly contrasty to a designer’s eye.
“Large text” has a specific definition and it is not what most people assume: 24px or larger, or 18.66px or larger if bold. The specification expresses these as 18pt and 14pt bold. A 20px heading is not large text and needs the full 4.5:1.
A second criterion, 1.4.11 Non-text Contrast, covers everything that is not text: 3:1 for user interface components and meaningful graphics. That means input borders, toggle states, focus indicators, and the parts of an icon that carry its meaning. It is newer than the text criterion and much more commonly missed, because teams check their body copy and never check the 1px grey border on their form fields.
Why is contrast the most common accessibility failure?
Because it is a design-time decision that nothing in a normal workflow challenges, and because the values that fail are the values that look sophisticated on a designer’s monitor.
WebAIM’s 2026 Million report found low contrast text on 83.9% of the top million home pages, up from 79.1% the year before. It has topped their list every year they have run it, and the trend is going the wrong way.
The pattern behind that number is worth naming. In our own scan of 4,135 pages across 92 sites, the strongest finding was that most accessibility failures repeat across a site rather than sitting in isolation, and contrast is the clearest case of it. One #999 defined once in a stylesheet becomes hundreds of findings across every page that uses it. The scanner reports hundreds of problems. There are usually about four.
That changes what “fixing contrast” means. It is not a page-by-page remediation job. It is a short list of colour values, and the work is in the tokens.
Which contrast failures show up most?
Five patterns account for most of what scanning surfaces:
- Grey microcopy. Helper text, timestamps, captions and disclaimers set in a light grey that was chosen to be visually quiet. Quiet and unreadable are close neighbours.
- Placeholder text used as a label. Fails twice over: the contrast is usually too low, and a placeholder is not a label in the first place.
- Brand colour on white. Many brand palettes were set before anyone checked. Mid-tone blues, greens and oranges frequently land between 3:1 and 4.5:1, passing for large text and failing for body.
- Text over hero images. The ratio is not one number here. It varies pixel by pixel, and it changes when the image is swapped by a content editor who never saw this requirement.
- Interface borders and states. The 1px
#dddinput border, the unfilled state of a toggle, the focus ring that is only slightly lighter than the background. All governed by 1.4.11, all routinely missed.
How do I fix contrast failures properly?
Change the token, not the element. That is the whole answer, and it is why contrast is the highest-leverage accessibility fix available to most teams.
The steps in practice:
- Find the failing values, not the failing pages. Group findings by the colour pair that produced them. A hundred findings usually collapse to a handful of pairs.
- Fix each pair once, in the design token. Darken the foreground or lighten the background until it passes. Small shifts usually suffice:
#999to#767676on white takes you from failing to passing without visibly changing the design’s temperament. - Check the interface states too. Hover, focus, disabled, error and selected are separate colour pairs and each needs its own check. This is where most remaining failures hide after the obvious text is fixed.
- Then check text over images. Add a scrim, a gradient overlay or a solid text panel. Relying on a photograph being dark enough is relying on whoever uploads the next photograph.
Note the CSS property is spelled color regardless of the rest of your codebase’s spelling, which trips up more style linters than it should.
Where does automated contrast checking stop working?
For plain text on a plain background, automated checking is close to definitive, and this is one of the few WCAG criteria where that is true. Two colour values, one formula, no judgement.
It stops being definitive in four situations, and building the rule made each of them concrete:
- Text over a photograph, gradient or video. There is no single background colour to measure. A scanner can sample, but a sample is not a guarantee, and the answer changes when the media changes.
- Text baked into an image. No text node exists in the DOM, so nothing is measured at all. The failure is invisible to the check rather than reported as a pass.
- Colours that depend on state. A hover or focus colour that a scanner never triggers is a colour it never evaluates.
- Anything behind a semi-transparent overlay. The computed result depends on stacking and blend modes, and getting it right requires resolving the whole stack rather than reading two declared values.
None of this makes automated contrast checking unreliable for the common case. It makes the common case the thing it covers. 1.4.3 is one of the criteria RedFlag checks automatically; the situations above are why the contrast rule also carries a manual note rather than reporting a clean pass and moving on.
The honest framing: run the scan to clear the mechanical failures, which will be most of them and will collapse into a few tokens. Then look at your hero images and your interface states with your own eyes, because that is the part the arithmetic cannot reach.
Frequently asked questions
What contrast ratio does WCAG require?
At Level AA, 4.5:1 for normal body text and 3:1 for large text, which means 24px and above, or 18.66px and above if bold. Level AAA raises those to 7:1 and 4.5:1. A separate criterion, 1.4.11, requires 3:1 for user interface components and meaningful graphics such as icons, input borders and focus indicators.
Does colour contrast apply to disabled buttons and placeholder text?
Disabled controls are explicitly exempt from the text contrast requirement. Placeholder text is not, because it is real text serving a purpose, and the common pattern of grey placeholder text on white usually fails. The safer answer for placeholders is to stop using them as labels at all.
How do I fix a contrast failure?
Darken the text or lighten the background until the ratio passes, and do it in the design token rather than on the element. Contrast failures cluster because a handful of colour values are reused across a whole site, so changing a token fixes every instance at once while changing one component fixes one component.
Can automated tools check colour contrast reliably?
For plain text on a plain background, yes, more reliably than almost any other WCAG check, because it is arithmetic on two colour values. It becomes unreliable when the background is a photograph, a gradient or a video, when the text is baked into an image, or when the computed colour depends on a state a scanner never triggers. Those cases need a person.