Code of the Day
IntermediateAccessibility

Color and Contrast

Color contrast is a mathematical ratio between foreground and background — WCAG sets minimum ratios that ensure text is readable for users with low vision.

Web FoundationsIntermediate6 min read
By the end of this lesson you will be able to:
  • Calculate whether a text/background pair meets WCAG contrast requirements
  • Distinguish the contrast requirements for normal text, large text, and UI components
  • Explain why color cannot be the only way to convey information
  • Test contrast using browser DevTools and the WebAIM Contrast Checker

Light gray text on a white background looks clean and modern. It also makes the page unreadable for the 246 million people with moderate to severe vision impairment worldwide, and for anyone reading on a phone in bright sunlight. is not a matter of taste — it is a mathematical property that can be measured and enforced.

The contrast ratio

WCAG defines contrast as a ratio derived from the relative luminance of two colours — a calculation that converts colour values into a representation of how bright they appear to the human eye. The result is expressed as a ratio from 1:1 (identical — no contrast at all) to 21:1 (pure black on pure white — the maximum possible contrast).

You do not need to perform this calculation by hand. Every tool in this ecosystem computes it for you. What you do need to know are the thresholds.

WCAG minimum contrast requirements

WCAG 2.1 Level AA sets the following minimums:

Content typeMinimum ratio
Normal text (below 18pt / 14pt bold)4.5:1
Large text (18pt or larger, or 14pt+ bold)3:1
UI components (button borders, input borders, icons)3:1
Decorative content, logos, disabled controlsNo requirement

Level AAA raises the bar to 7:1 for normal text and 4.5:1 for large text. These are aspirational targets; 2.1 AA (4.5:1) is the standard baseline.

A few practical examples of what passes and what fails:

/* PASSES: #767676 on white (#fff) — ratio is exactly 4.54:1 */
color: #767676;
background: #ffffff;

/* FAILS: #999 on white — ratio is 2.85:1 */
color: #999999;
background: #ffffff;

/* PASSES for large text, FAILS for body copy: #aaa on white — ratio is 2.32:1 */
/* Large text at 18px+ can use a lower bar, but 2.32 fails even that */
color: #aaaaaa;
background: #ffffff;

/* PASSES: classic high contrast — white on dark blue */
color: #ffffff;
background: #003580; /* ratio: 8.4:1 */

Checking contrast

You have three practical tools:

Browser DevTools — in Chrome and Firefox, click any text element and open the Computed tab (Chrome) or the Accessibility panel (Firefox). The colour picker in the Styles pane shows the contrast ratio and a pass/fail indicator next to the foreground colour swatch.

WebAIM Contrast Checker — paste two hex codes at webaim.org/resources/contrastchecker and it instantly computes the ratio with pass/fail for both AA and AAA levels.

Browser extensions — axe DevTools and the Colour Contrast Analyser can scan an entire page and flag every failing pair at once, which is faster than checking elements individually.

Placeholder text inside form inputs is a common failure. Browsers render placeholder text in a light grey by default — typically around a 1.9:1 ratio. Either style it to meet the 4.5:1 minimum or treat it as decorative and ensure the label carries all the essential information.

The color-alone rule

WCAG 1.4.1 (Use of Color) prohibits using colour as the only visual means of conveying information. This affects more situations than most developers expect:

Required field indicators — marking required fields with a red asterisk only fails for users with red-green colour blindness. Add a text label ("required") or a visually distinct shape.

Error states — showing an error by turning a border red only is insufficient. Add an icon, change the border style, or add an error message in text.

Charts and graphs — a pie chart where the only differentiator between segments is colour is inaccessible to colour-blind users. Add labels, patterns, or textures.

Links in body text — links that differ from surrounding text only by colour fail this criterion. They must also have an underline, bold, or other non-colour distinction. (The default browser underline is fine — many designs remove it and forget to add an alternative.)

<!-- Wrong: color alone indicates the error -->
<input type="text" style="border-color: red;">

<!-- Right: color + icon + text communicate the error -->
<input type="text" style="border-color: red; border-width: 2px;" aria-invalid="true" aria-describedby="name-error">
<p id="name-error">
  <span aria-hidden="true">⚠</span> Name is required.
</p>

Dark mode and prefers-color-scheme

If you support a dark theme, contrast must be verified in both modes. A palette that passes in light mode can fail in dark mode if colours are inverted naively. Use the prefers-color-scheme media query and test both branches:

/* Light mode defaults */
:root {
  --text: #1a1a1a;
  --background: #ffffff;
  --muted: #595959; /* 7:1 on white */
}

@media (prefers-color-scheme: dark) {
  :root {
    --text: #f0f0f0;
    --background: #121212;
    --muted: #b0b0b0; /* must re-verify: 6.8:1 on #121212 — passes */
  }
}

Color blindness: beyond contrast

About 8% of men and 0.5% of women have some form of colour vision deficiency. The most common type (deuteranopia / protanopia) makes it difficult to distinguish red from green. Contrast ratio does not directly address colour blindness — a dark red on dark green can have adequate contrast as a ratio but still be indistinguishable to a colour-blind user.

For data visualisations, use patterns or textures alongside colour, include direct labels on chart segments, and consider a colour-blind simulation tool (Colorblind Web Page Filter, or the Emulate vision deficiencies option in Chrome DevTools) to check your palette.

Where to go next

You can now check and fix contrast problems with confidence. Next: Testing Accessibility — how to use automated tools, keyboard tests, and a screen reader to find the problems your code review missed.

Finished reading? Mark it complete to track your progress.

On this page