How to fix insufficient color contrast?

color-contrast Serious WCAG 2.1 · 1.4.3 Contrast (Minimum)

Elements must meet minimum color contrast ratio thresholds

Element has insufficient contrast ratio of 2.54:1 (foreground: rgb(156, 163, 175), background: rgb(255, 255, 255)). Required 4.5:1 for WCAG AA

The issue

Text that is too close in brightness to its background is hard to read, and for some readers impossible. A ratio that reads comfortably on a calibrated monitor in a dim room can vanish on a phone in sunlight. Below the threshold the text is still in the page and a screen reader still reads it, but a sighted reader who depends on contrast loses it.

Contrast is not a matter of taste. It is a ratio computed from the relative luminance of two colors, from 1:1 for identical colors to 21:1 for black on white. WCAG sets a minimum of 4.5:1 for normal text and 3:1 for large text. Red–green color vision deficiency affects up to 8% of men and 0.5% of women of Northern European descent (Almustanyir, 2025), and everyone loses contrast to screen glare, low brightness and aging eyes.

Scope

Every page is judged on its own, because contrast depends on the colors that page actually renders. Each visible element that holds text is checked. Text directly inside form fields, buttons, images and SVG is skipped, and so are hidden elements. If the site has a dark mode, it is a second set of color pairings and can fail where the light one passes.

How to check you have it

  • In probeo: the page reports the color-contrast rule, “Elements must meet minimum color contrast ratio thresholds”, with the measured ratio, both colors and the ratio required.
  • By hand: in Chrome DevTools, inspect the text and open the color picker for its color. It shows the contrast ratio against the background and whether it meets AA and AAA.
  • Dark mode: switch the page to its dark scheme and check again.

How probeo measures it

Probeo runs this check on every page it manages, each time it reads the page. It uses the color-contrast rule from its accessibility checker, which follows axe-core’s rule of the same name. For each element that holds text, probeo works out the text color and the background color behind it:

  • It reads colors from the element’s inline styles and from the page’s own <style> blocks, following CSS custom properties (var(--text)) to their values.
  • The text color is inherited from the nearest ancestor that sets one. The background is the nearest ancestor’s background color.
  • A semi-transparent text color is blended onto its background first, so the ratio is the one a reader sees.
  • Font size and weight decide whether the text counts as large. A rem is taken as 16px.

It then computes the ratio with the WCAG formula and records whether the text meets AAA, meets AA, or fails.

When probeo says it can’t tell

Some contrast can’t be measured from the page’s HTML alone. In these cases probeo marks the element as undetermined rather than guessing, and it does not count as a failure:

  • A background image or gradient sits behind the text. The effective background changes from point to point.
  • The colors come from a linked stylesheet. Probeo reads the HTML it captures and does not load separate CSS files, so colors defined only there are unknown.
  • A color can’t be resolved, such as currentColor or inherit with nothing to inherit from.

Only simple selectors in <style> blocks are applied: a tag, a class, an id, or a combination of those. A color set through a more complex selector is not seen, so for those elements the measured color can differ from what a browser draws. A failure probeo reports is a measured failure, but a page with no failures has not been proven to pass. Check the undetermined elements by hand.

The fix

Change the text color, the background, or both, until the ratio clears the threshold.

Small shifts usually do it: lightening a background or darkening text by a few percent can move 4.2:1 to 4.6:1 without changing the look of the design. Fix it where the color is defined. If the site uses a design system or CSS variables, one change to the token fixes every page that uses it:

:root {
  --text-muted: #6b7280; /* 4.8:1 on white, was #9ca3af at 2.5:1 */
}

Then look for the places a token doesn’t reach: inline styles, colors set by scripts, and overrides on individual pages. Text over images needs its own treatment, usually a semi-transparent overlay between the image and the text so the contrast holds whatever the image shows.

Done when: text meets 4.5:1, or 3:1 if it is large, controls, icons and focus indicators meet 3:1 against what surrounds them, and the check above comes back clean. On its next read of the page, probeo measures again and the finding clears.

Do not

  • Do not shrink text to slip under the large-text threshold.
  • Do not judge by eye; use a checker that computes the WCAG ratio.
  • Do not exempt placeholder text, link text or navigation.
  • Do not assume a pairing that passes on one background passes on all of them.

What WCAG asks for

There are two levels. Most sites hold themselves to AA; AAA narrows the palette a good deal.

Level Normal text Large text
AA (1.4.3) 4.5:1 3:1
AAA (1.4.6) 7:1 4.5:1

Large text is at least 18pt (24px), or 14pt (about 18.7px) when bold. Under 1.4.11, non-text elements a reader needs in order to use the page, such as input borders, icons and focus indicators, need 3:1 against the colors next to them.

Some text is exempt. Text in a logo or brand name, text on a disabled control, and text that is pure decoration have no minimum.

FAQ

Are disabled form elements exempt?

Yes. WCAG exempts inactive controls. A disabled button that can’t be used doesn’t need to meet 4.5:1 or 3:1. If its disabled state tells the reader something they need, such as which options are unavailable, say it in a way that doesn’t rely on color.

Does placeholder text need to meet the ratio?

Yes, when it does the work of a label or gives instructions the reader needs. Light gray placeholder text on white often fails. If the field has its own visible label and the placeholder is only an example, it matters less, but automated checks will still flag it.

Do logos need to meet the ratio?

No. Text in a logo or brand name is exempt. The exemption doesn’t extend to taglines, navigation in brand colors, or body text set in the brand palette.

What contrast do focus indicators need?

3:1 against the colors next to them, under 1.4.11. WCAG 2.2 adds 2.4.13 Focus Appearance, which also sets a minimum size and a 3:1 change between the focused and unfocused states. Removing focus outlines with CSS is a separate failure.

How is contrast measured over images or gradients?

At the point behind the text where contrast is lowest. Probeo can’t measure this from the HTML and marks it undetermined. An overlay that guarantees the minimum, whatever the image shows, is the usual fix.

Does dark mode need its own check?

Yes. Each color scheme is its own set of pairings, and each has to meet the thresholds.

Which product detects this

Probeo checks this on every page of your site as part of Site Clarity. This page explains one instance; the product tells you every page that has it.