Skip to content

Accessibility

Color contrast in WCAG: text and non-text

The WCAG contrast ratios for text (1.4.3) and for controls, focus indicators and graphics (1.4.11), how they are measured, and the fixes that pass.

Your UX Agent teamProduct
10 min read

WCAG sets two contrast minimums at Level AA. Text needs a contrast ratio of at least 4.5:1 against its background, or 3:1 if it is large (1.4.3).

The parts of controls and graphics that people need to see, such as a focus indicator, a checkbox’s outline or a line in a chart, need 3:1 against the colours next to them (1.4.11).

Our checklist has a failing and a passing example for 1.4.3, and for 1.4.11 further on.

The ratios at a glance

Applies toCriterionLevelMinimum
Text1.4.3AA4.5:1
Large text1.4.3AA3:1
Text1.4.6AAA7:1
Large text1.4.6AAA4.5:1
Controls, their states, focus indicators1.4.11AA3:1 against adjacent colours
Parts of graphics needed to understand them1.4.11AA3:1 against adjacent colours
The WCAG contrast minimums

Large text is at least 18 point, or 14 point bold. In CSS pixels that is 24px, or 18.67px at a bold weight. The size is the one the page is delivered at, not what a visitor zooms to.

How the ratio is calculated

The contrast ratio compares the relative luminance of two colours, how bright each is on a scale from 0 for black to 1 for white:

The WCAG contrast ratio
ratio = (L1 + 0.05) / (L2 + 0.05)​L1: luminance of the lighter colourL2: luminance of the darker colour​L = 0.2126 R + 0.7152 G + 0.0722 B

R, G and B are the colour’s red, green and blue channels, each converted from 0–255 to a linear scale before they are added. The result runs from 1:1, two identical colours, to 21:1, black on white.

Three rules about the number matter in practice:

  • Do not round. The W3C is explicit: 4.499:1 does not meet 4.5:1. Grey #767676 on white is 4.54:1 and passes; #777777, one step lighter, is 4.48:1 and fails.
  • Measure the colours as specified. The ratio uses the colours in the stylesheet or the browser’s computed values, not a screenshot, which anti-aliasing blurs.
  • Measure against the real background. If a text colour is set and no background is, the background is unknown, which the W3C counts as a failure, and the same applies to a background set without a text colour. With neither set, white is assumed.

Text that fails, and text that is exempt

Grey body text is the familiar failure, but not the only one:

  • Placeholder text in a form field is text, and 1.4.3 applies to it.
  • Text on hover or focus, such as a tooltip or a button’s hover colour, has to pass in that state too.
  • Text over an image passes only if it passes over the parts of the image it actually sits on. A dark overlay or a solid panel behind the text fixes it.
  • Text on a gradient has to pass where contrast is lowest behind the text, not on average.
  • Semi-transparent text blends with what is behind it; measure the colour that results, not the colour in the stylesheet.
  • Thin fonts render fainter than their colour suggests. The W3C suggests a font with thicker strokes, or a ratio above the minimum.

Four kinds of text have no requirement: text in a disabled control, text that is pure decoration, text that nobody can see, and text that is part of a picture with significant other visual content. Text in a logo or brand name is exempt too.

Controls and graphics

1.4.11 asks for 3:1 against adjacent colours for the visual information people need to identify a control and its state, and for the parts of a graphic they need to understand it:

  • Text fields. A field needs a visible boundary only if nothing else shows where it is. A field shown only by a background colour needs that background to reach 3:1 against the page.
  • Checkboxes, radio buttons and switches: the box outline and the check mark or selected state.
  • Icons that carry meaning without text, such as a status icon on a dashboard.
  • Charts: each line, bar or segment needed to read the chart, against the colours next to it. Segments that touch need 3:1 against each other, or a contrasting border between them. Visible labels and values that give the same information also work.

Inactive controls are exempt, as are controls left in the browser’s default style, logos, and graphics whose particular presentation is essential, such as a photograph. Hover effects are extra and do not need 3:1, because the pointer already shows where you are. Our checklist has the 1.4.11 pass and fail.

Focus indicators

At Level AA, a focus indicator falls under 1.4.11: it needs 3:1 against the colours next to it. The browser’s own default focus ring is exempt, but it must still be visible. The criterion does not compare the focused state with the unfocused one.

The AAA criterion 2.4.13 Focus Appearance goes further. The indicator has to cover an area at least as large as a 2 CSS pixel thick line around the unfocused control, and those pixels need 3:1 between the focused and unfocused states, unless you leave the browser’s indicator and its background unchanged.

A focus ring that passes on a white page can fail on a dark header:

Fails on a dark surface: one ring colour everywhere
:focus-visible {  /* 6.39:1 on white,     2.73:1 on #1a1a1a */  outline: 2px solid #0b57d0;  outline-offset: 2px;}
Passes: a ring colour for each surface
:focus-visible {  outline: 2px solid var(--color-focus);  outline-offset: 2px;}​:root {  /* 6.39:1 on white */  --color-focus: #0b57d0;}​.surface-dark {  /* 8.26:1 on #1a1a1a */  --color-focus: #8ab4f8;}

A visible indicator also has to stay in view when the page scrolls; see focus hidden behind sticky headers and cookie banners.

A link that looks different from the text around it only by colour fails 1.4.1 Use of Color, unless the colours differ enough. The W3C’s sufficient technique is a ratio of at least 3:1 between the link colour and the surrounding text, on top of the 4.5:1 each needs against the background. An underline is simpler, and it works for everyone.

Fix it in the design tokens

Contrast failures come back when each component picks its own colours. Fix them where the colours are defined, once, and pair each colour with the surface it is allowed on:

Fails: tokens that do not pass on their surfaces
:root {  /* 2.61:1 on white */  --color-text-muted: #a0a0a0;  /* 1.82:1 on white */  --color-border-input: #c0c0c0;  --color-surface-card: #f5f5f5;}​.card .meta {  /* 4.54:1 on white,     but 4.17:1 on the card */  color: #767676;}
Passes: each token checked against its surface
:root {  --color-surface: #ffffff;  --color-surface-card: #f5f5f5;  /* 5.33:1 on white, 4.89:1 on card */  --color-text-muted: #6b6b6b;  /* 3.36:1 on white, 3.08:1 on card */  --color-border-input: #8c8c8c;}​.card .meta {  color: var(--color-text-muted);}

The grey that passed on white fails on a light grey card, which is why a token’s value has to be checked against every surface it is used on, not only the page background. Record the ratios next to the tokens, as here, so the next change is checked too.

How to test contrast

  1. Run an automated check on each page template, in a real browser, at a phone width and a desktop width.
  2. Check the states a scan may not reach: hover, focus, error and selected, and that a control that looks disabled really is inactive.
  3. Check text over images and gradients by eye, or with a colour picker on the point behind the text where contrast is lowest.
  4. Check focus indicators by tabbing through the page, including on dark surfaces.
  5. Check charts and icons against their background and against each other.

axe-core’s color-contrast rule checks 1.4.3 and is on by default; its AAA rule, color-contrast-enhanced, is off by default, and axe-core 4.14.0 has no rule for 1.4.11. Its link-in-text-block rule checks links that rely on colour. Text over images, the meaning of icons and charts, and which parts of a control matter need a person.

Why contrast has a AA and a AAA criterion, and what each level means, is in our explainer on WCAG’s levels A, AA and AAA.

Frequently asked questions

What contrast ratio does WCAG require?

At Level AA, 4.5:1 for text and 3:1 for large text (1.4.3), and 3:1 for the parts of controls, focus indicators and graphics people need to see (1.4.11). At Level AAA, 7:1 for text and 4.5:1 for large text (1.4.6).

What counts as large text in WCAG?

At least 18 point, or 14 point bold: 24 CSS pixels, or about 18.7 CSS pixels at a bold weight.

Does placeholder text need to meet contrast requirements?

Yes. 1.4.3 applies to placeholder text, and to text shown on hover.

Do disabled buttons need to meet contrast requirements?

No. Text and controls in an inactive component are exempt from 1.4.3 and 1.4.11. A control that only looks disabled but still works is not exempt.

Is 4.49:1 enough to pass 4.5:1?

No. The W3C says not to round: 4.499:1 does not meet 4.5:1.