Colour contrast and WCAG: what AA and AAA mean, with examples
8 min read · Updated 4 October 2026
Low-contrast text is one of the most common accessibility problems on the web. Light grey text on a white background may look elegant on a designer's high-end monitor, but on a phone in sunlight, on a cheap laptop screen, or for someone with low vision or a colour vision deficiency, it can be hard or impossible to read.
The Web Content Accessibility Guidelines (WCAG) give a precise, measurable definition of "enough contrast". This guide explains how that number is calculated, what the AA and AAA levels require, and how to fix colours that fail, with real colour pairs and their actual ratios.
The contrast ratio
WCAG compares two colours using their relative luminance: how bright each colour appears, on a scale from 0 (black) to 1 (white). The contrast ratio is:
(L1 + 0.05) / (L2 + 0.05)
where L1 is the luminance of the lighter colour and L2 that of the darker one. The result ranges from 1:1 (two identical colours) to 21:1 (black on white). The 0.05 accounts for light reflected from the screen and stops the formula dividing by zero for pure black.
Luminance is not a simple average of red, green and blue. The calculation first converts each channel from the sRGB values stored in the file into linear light, then weights them roughly according to how sensitive our eyes are to each:
L = 0.2126 × R + 0.7152 × G + 0.0722 × B
Green dominates and blue counts for very little. That is why pure yellow (#FFFF00) is almost as bright as white, while pure blue (#0000FF) is very dark, even though both use the full value of their channels.
You never need to do this by hand: the contrast checker calculates the ratio for any pair of colours and shows which levels it meets.
The thresholds
WCAG 2.2 sets these minimums for text:
| Level | Normal text | Large text |
|---|---|---|
| AA | 4.5:1 | 3:1 |
| AAA | 7:1 | 4.5:1 |
Large text means at least 18 point (24 CSS pixels) at a regular weight, or at least 14 point (about 18.7 CSS pixels) in bold. Larger, heavier letters are easier to read at lower contrast, so they get a lower threshold.
AA is the level most laws, policies and procurement rules refer to, and the sensible target for any website. AAA is stricter. It is a good goal for body text where you can achieve it, but WCAG itself notes that AAA is not expected for all content.
There is also a requirement for non-text contrast at level AA: parts of the interface needed to understand or operate it (input field borders, checkbox outlines, icons that carry meaning, focus indicators, chart lines) need a ratio of at least 3:1 against the colours next to them.
Real examples
These ratios are calculated with the WCAG formula. All are against a white background (#FFFFFF) unless noted.
| Foreground | Ratio | Normal text AA | Large text AA | Normal text AAA |
|---|---|---|---|---|
#000000 black |
21.00:1 | Pass | Pass | Pass |
#595959 dark grey |
7.00:1 | Pass | Pass | Pass |
#6B7280 slate grey |
4.83:1 | Pass | Pass | Fail |
#767676 mid grey |
4.54:1 | Pass | Pass | Fail |
#777777 mid grey |
4.48:1 | Fail | Pass | Fail |
#FF0000 pure red |
4.00:1 | Fail | Pass | Fail |
#999999 light grey |
2.85:1 | Fail | Fail | Fail |
#CCCCCC pale grey |
1.61:1 | Fail | Fail | Fail |
A few things stand out:
#767676passes and#777777fails. One step of difference in each channel moves the ratio from 4.54 to 4.48, across the 4.5 line. Thresholds are strict: 4.48 is not "close enough".- Pure red on white fails for normal text. Red error messages are a classic problem; a darker red is needed.
- Light greys used for "secondary" text (dates, captions, placeholder text) often fail by a wide margin.
White text on coloured backgrounds:
| Background | White text ratio | Normal text AA |
|---|---|---|
#0066CC blue |
5.57:1 | Pass |
#2563EB bright blue |
5.17:1 | Pass |
#008000 green |
5.14:1 | Pass |
#FF8800 orange |
2.39:1 | Fail |
#FFCC00 yellow |
1.51:1 | Fail |
Orange is a common brand colour that does not work behind white text. The same orange behind black text reaches 8.77:1, which passes even AAA. When a brand colour fails with white, switching the text to black (or very dark grey) is often the simplest fix.
Interface elements: the 3:1 rule
Text is not the only thing that needs contrast. A text input whose border is #D1D5DB on a white page has a ratio of only 1.47:1, so many people cannot see where the field is. Darkening the border to #949494 gives 3.03:1, which meets the 3:1 requirement for non-text elements; #8A8A8A gives 3.45:1 if you want a little margin.
The same applies to:
- checkbox and radio button outlines;
- icons used without a text label, such as a magnifying glass for search;
- the keyboard focus indicator that shows which element is selected;
- lines and areas in charts that carry information.
Purely decorative elements (background shapes, dividers that are not needed to understand the layout) do not need to meet it.
What is exempt
WCAG's contrast requirements do not apply to:
- Logos and brand names that are part of a logo.
- Disabled controls: buttons or fields that cannot be used. (Make sure it is still clear that they are disabled.)
- Incidental text: text in a photo that is not important, decorative text, or text in an inactive part of the interface.
Placeholder text inside form fields is not exempt when it conveys information, and it is very often too light.
Tricky situations
Text on images and gradients. The ratio varies across the image. Check the text colour against the lightest (or darkest) area it overlaps, not the average. A semi-transparent dark overlay behind the text, or a solid panel, makes the result predictable.
Transparency. A text colour with 60% opacity is effectively a blend with the background. Contrast tools need the final blended colour; if your design uses opacity, measure the rendered colour.
Hover, focus and visited states. Every state needs to pass, not only the default. A link that turns light grey on hover fails while the mouse is over it.
Links in body text. If links are shown only by colour (no underline), people who cannot distinguish the colours may not find them. Underlines are the simplest solution. If you remove them, the link colour needs clear contrast with the surrounding text as well as the background, plus a non-colour cue on hover and focus.
Dark mode. A dark theme needs its own check. White text on #121212 is 18.73:1, which is comfortable. Mid-grey secondary text such as #6B6B6B on that background is only 3.52:1, which fails for normal text; #9E9E9E gives 6.99:1.
How to fix colours that fail
Usually you can keep the same hue and only change the lightness:
- Enter the failing pair in the contrast checker. It suggests the nearest colours that pass, adjusting the foreground or the background.
- Darken text on light backgrounds, or lighten text on dark backgrounds, until the ratio reaches 4.5:1 for normal text. Aim a little above the line (for example 4.6:1 or more) so rounding in design tools does not push you below it.
- Update your palette, not just the one element, so the corrected colour is used consistently. The colour palette generator lets you adjust colours in OKLCH, a colour space where changing lightness keeps the hue looking the same, and checks contrast between swatches.
Two worked fixes:
- A link colour of
#3B82F6on white is 3.68:1, which is fine for large headings, but it fails for body text. The darker#2563EBreaches 5.17:1 and still reads as the same bright blue. - Error text in pure red
#FF0000is 4.00:1. Moving to#CC0000gives 5.89:1 and still looks unmistakably red.
Automated checks and their limits
Automated tools find many contrast problems quickly. Paste a page's HTML into the accessibility checker, which runs the axe-core rules and reports low-contrast text alongside other issues such as missing labels and alt text.
But automated contrast checks have blind spots:
- They cannot reliably measure text over background images or complex gradients, so they report those as "needs review" rather than pass or fail.
- They may not see hover and focus states unless those states are active.
- They check text in the HTML, not text inside images.
So combine automated checks with a quick manual review of hero images, buttons in every state, and charts.
A note on WCAG 3 and APCA
A different contrast method called APCA has been proposed for the future WCAG 3. It accounts for font size and weight more precisely and treats light-on-dark differently from dark-on-light. WCAG 3 is still a draft, and the 2.x ratios remain the requirement that laws and policies refer to. Meeting WCAG 2.2 AA is the right target today.
Common mistakes
- Light grey text for captions, dates, footers and placeholders.
- White text on yellow, orange or light green buttons.
- Relying on the design file instead of the built page, where opacity and anti-aliasing change the result.
- Checking only the default state of buttons and links.
- Fixing one colour on one page instead of updating the design system.
FAQ
Is 4.5:1 rounded? No. WCAG compares the exact ratio with the threshold, so 4.48:1 fails AA for normal text even though it would round to 4.5.
Does contrast apply to placeholder text? Yes, if the placeholder conveys information. Better still, use a visible label above the field and do not rely on placeholders for instructions.
Is pure black on pure white the best choice?
It gives the maximum ratio, 21:1. Some readers find it harsh on bright screens, and very dark grey on off-white (for example #1A1A1A on white, 17.40:1) is a popular compromise that still exceeds AAA.
Do I have to meet AAA? AA is the usual requirement. Meeting AAA for body text is good practice when your design allows it, but it is not expected for every element.