Type something to search...
What Are WCAG Contrast Requirements for Text?

What Are WCAG Contrast Requirements for Text?

Your brand's primary blue looks great on a white button in Figma. Then an accessibility audit comes back and flags every button on the site, along with your placeholder text, your footer links, and the light gray captions under each image. The designer insists the colors "look fine," and on a calibrated monitor in a dark office they probably do. But contrast isn't a matter of opinion under WCAG. It's a number calculated from the two colors, and either it clears the threshold or it doesn't.

This article explains exactly what the WCAG contrast requirements for text are, what counts as large text, how the contrast ratio is calculated, which text is exempt, how to test it, and how to fix failures without abandoning your brand palette.

What Is a Contrast Ratio?

A contrast ratio compares the relative luminance (perceived brightness) of a foreground color and its background. It ranges from 1:1 (identical colors, invisible text) to 21:1 (pure black on pure white). Higher numbers mean text stands out more clearly.

The ratio only considers luminance, not hue. Red text on a green background can have very different colors and still have a ratio close to 1:1, which is precisely the kind of pairing that people with red-green color blindness can't read. Measuring luminance gives a result that holds for most types of color vision.

Some reference points, all on a white background:

Text colorContrast on whiteResult
#00000021:1Passes everything
#33333312.63:1Passes AAA
#5959597.0:1Just passes AAA for normal text
#7676764.54:1Darkest-looking gray that barely passes AA
#7777774.48:1Fails AA for normal text
#9494943.03:1Passes only for large text
#9999992.85:1Fails everything

Notice how close #767676 and #777777 are. One step of gray is the difference between passing and failing, which is why you have to measure rather than eyeball it.

The WCAG Text Contrast Thresholds

WCAG 2.2 has two text contrast criteria and one for non-text elements:

1.4.3 Contrast (Minimum), Level AA

  • Normal text: at least 4.5:1
  • Large text: at least 3:1

This is the requirement most laws and policies reference, including Section 508 in the US, EN 301 549 in Europe, and the European Accessibility Act.

1.4.6 Contrast (Enhanced), Level AAA

  • Normal text: at least 7:1
  • Large text: at least 4.5:1

AAA isn't usually required across a whole site, but it's a good target for long-form body text, where readers spend the most time.

1.4.11 Non-text Contrast, Level AA

  • UI components and graphical objects: at least 3:1 against adjacent colors.

This covers input borders, focus indicators, icons that convey meaning, checkbox outlines, and chart elements. It doesn't apply to text itself, but it often affects text-related UI, such as the border around a search field or the underline on a focused link.

What Counts as Large Text?

WCAG defines large text as:

  • At least 18 point regular weight, which is 24 CSS pixels, or
  • At least 14 point bold, which is about 18.66 CSS pixels at a weight of 700 or more.

A few details trip people up:

  1. CSS pixels, not device pixels. A 24px heading is large text on any screen. The physical size on a phone doesn't matter.
  2. Bold means bold. A weight of 600 (semibold) in a typeface that looks heavy doesn't automatically qualify. The safest interpretation is 700 or above.
  3. Thin fonts don't get a pass. A 24px heading in a hairline weight technically qualifies as large text, but it may still be very hard to read. The WCAG Understanding document notes that fonts with very thin strokes need more contrast than the minimum.
  4. Zoom doesn't change the category. Text that's 16px doesn't become large text because a user can zoom to 200%. Measure at the default size.

If you're tempted to bump body text to 24px to use the 3:1 threshold, don't. Pick colors that pass 4.5:1 for all body text instead.

How the Contrast Ratio Is Calculated

The formula comes from the WCAG definition of relative luminance in the sRGB color space.

  1. Convert each 8-bit RGB channel to a value between 0 and 1 by dividing by 255.
  2. Linearize each channel: if the value is 0.04045 or less, divide it by 12.92. Otherwise, compute ((value + 0.055) / 1.055) raised to the power of 2.4.
  3. Compute luminance: L = 0.2126 × R + 0.7152 × G + 0.0722 × B.
  4. Compute the ratio: (L1 + 0.05) / (L2 + 0.05), where L1 is the lighter color.

Green carries most of the weight in that formula, which is why yellow and light green fail so easily on white while blue often passes.

Here's the same calculation in TypeScript, useful for checking design tokens in a build script or test:

function channel(value: number): number {
  const c = value / 255;
  return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}

function luminance(hex: string): number {
  const h = hex.replace("#", "");
  const [r, g, b] = [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
  return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
}

export function contrastRatio(fg: string, bg: string): number {
  const [light, dark] = [luminance(fg), luminance(bg)].sort((a, b) => b - a);
  return (light + 0.05) / (dark + 0.05);
}

// contrastRatio("#767676", "#ffffff") -> 4.54
// contrastRatio("#777777", "#ffffff") -> 4.48

WCAG doesn't allow rounding up. A ratio of 4.48:1 fails 4.5:1, even though it rounds to 4.5.

What Text Is Exempt?

WCAG 1.4.3 has three exceptions:

  • Incidental text. Text in an inactive (disabled) UI component, purely decorative text, text that isn't visible to anyone, and text that's part of a picture containing significant other visual content, such as a street sign in a photo.
  • Logotypes. Text that's part of a logo or brand name has no contrast requirement.
  • Large-scale text is not exempt, but it has the lower 3:1 threshold.

Things that are not exempt, despite common assumptions:

  • Placeholder text in form fields. If it conveys information, it must meet 4.5:1. Better still, don't rely on placeholders as labels.
  • Footer text and legal copy. Small print still needs to pass.
  • Text on hover or focus states. Every state that displays text needs to pass.
  • Text over images, videos, and gradients. You must check the worst-case area behind the text.

Disabled buttons are exempt, but that doesn't mean they should be invisible. Users still need to know a control exists and why it's unavailable.

How to Test Text Contrast

Use more than one method, because each catches different things.

Browser DevTools

In Chrome and Edge, inspect a text element and click the color swatch in the Styles panel. The color picker shows the contrast ratio with AA and AAA lines drawn across the color field. Firefox's Accessibility Inspector can scan a page for contrast issues and highlight each failing element.

Automated scanners

Lighthouse, axe DevTools, and WAVE all flag contrast failures on solid backgrounds. Run Lighthouse from the command line in CI:

npx lighthouse https://example.com --only-categories=accessibility --output=json --output-path=./a11y.json

Automated tools struggle with text over images and gradients, and they can't evaluate pseudo-elements or text revealed by interaction reliably, so treat a clean result as a starting point.

Dedicated checkers

The WebAIM Contrast Checker and the TPGi Colour Contrast Analyser (a desktop app with an eyedropper) are good for checking specific pairs and for sampling colors from screenshots, mockups, or images.

Check your tokens in code

If your colors live in a design token file, run the contrastRatio function above against every text and background pair in CI so a new token can't ship if it fails.

How to Fix Contrast Failures Without Losing Your Brand

You rarely need to change your brand color itself. You need to change where and how it's used.

  1. Darken text shades, keep the fill. Generate a darker tint of the brand color for text and links, and keep the original for backgrounds, illustrations, and large decorative elements.
  2. Swap text color on colored buttons. White on Tailwind's #3b82f6 blue is 3.68:1, which fails for normal text. White on #2563eb is 5.17:1 and passes. A one-step darker background is often enough.
  3. Use the large-text threshold deliberately. A brand orange that fails at 16px may pass 3:1 at 24px for a headline. Use it there, not in body copy.
  4. Add overlays behind text on images. A semi-transparent dark gradient under the caption gives you a predictable background to measure against.
  5. Retire "muted" grays that fail. On white, #6b7280 (4.83:1) is about as light as body-adjacent gray text should go.

Here's a practical token setup with tested pairs:

:root {
  --color-bg: #ffffff;
  --color-text: #1f2937;       /* 14.68:1 */
  --color-text-muted: #4b5563; /* 7.56:1 */
  --color-link: #2563eb;       /* 5.17:1 */
  --color-btn-bg: #2563eb;
  --color-btn-text: #ffffff;   /* 5.17:1 */
}

.hero-caption {
  background-image: linear-gradient(to top, rgb(0 0 0 / 0.75), transparent);
  color: #ffffff;
}

Do not forget dark mode

Every pair must be checked again in dark mode. #9ca3af gray text, which fails at 2.54:1 on white, passes at 6.99:1 on #111827. The reverse also happens: colors that work on white fail on dark backgrounds. If you support both themes, test both. The post on choosing fonts for dark mode covers the typographic side of dark themes.

What About APCA and WCAG 3?

The draft WCAG 3 work has explored a different contrast model called APCA (Accessible Perceptual Contrast Algorithm). It accounts for font size, weight, and polarity (dark text on light versus light on dark), which the WCAG 2 formula ignores. APCA tends to be stricter for light text on dark backgrounds and more forgiving for some dark-on-light mid-tones.

As of 2026, WCAG 3 is still a working draft, and APCA is not a conformance requirement. Legal and procurement standards reference WCAG 2.x. Use the 2.x ratios to meet requirements, and use APCA as an additional signal if you want, especially for thin fonts and dark themes.

Contrast Is Only One Part of Readable Text

Passing 4.5:1 doesn't make text readable on its own. A light 300-weight font at 14px can pass the ratio and still be difficult to read because its strokes are so thin. Contrast interacts with size, weight, and the typeface itself. For the complete picture, see how to make website typography accessible, and for verifying real-world legibility, how to test typography for low-vision users.

WCAG Contrast FAQ

WCAG 2.2 Level AA requires at least 4.5 to 1 for normal text and 3 to 1 for large text. Large text means at least 24 CSS pixels at regular weight or about 18.66 CSS pixels at bold weight.

Level AAA requires at least 7 to 1 for normal text and 4.5 to 1 for large text. AAA is rarely required for an entire site, but it is a sensible target for long-form body text.

No. WCAG treats the thresholds as exact minimums, so 4.48 to 1 fails the 4.5 to 1 requirement. Darken the text or lighten the background until the calculated ratio is at or above the threshold.

Yes. Placeholder text is not exempt and must reach 4.5 to 1 if it conveys information. Because placeholders disappear when users type, it is better to use a visible label and keep placeholders for optional examples.

No. Text that is part of a logo or brand name is exempt from the contrast criteria. Any other text near the logo, such as a tagline in the header, still needs to pass.

Find the lightest area of the image that sits behind light text, or the darkest area behind dark text, and measure against that point. If the result fails or the image may change, add a solid or gradient overlay behind the text to guarantee a consistent background.

No. APCA is part of exploratory work for WCAG 3, which is still a draft. Current legal and procurement standards reference the WCAG 2.x contrast ratios, so those are what you must meet.

Conclusion

The WCAG contrast rules are refreshingly concrete: 4.5:1 for normal text, 3:1 for text that's at least 24px or 18.66px bold, 7:1 if you're aiming for AAA, and 3:1 for meaningful UI boundaries and focus indicators. The ratio is calculated from luminance alone, it can't be rounded up, and only logos, disabled controls, and purely decorative text are exempt.

Fixing failures is usually a matter of using darker tints for text, choosing the right text color on colored buttons, adding overlays behind text on images, and testing both light and dark themes. Bake the checks into your design tokens and CI, and contrast stops being an audit finding and becomes a solved problem.

Here are some useful references for going deeper on WCAG contrast requirements:

  1. W3C WAI: Understanding Success Criterion 1.4.3: Contrast (Minimum) — the official explanation, including exemptions and the large-text definition.
  2. W3C WAI: Understanding Success Criterion 1.4.11: Non-text Contrast — requirements for borders, icons, and focus indicators.
  3. W3C: WCAG 2.2 definition of relative luminance — the exact formula used to calculate contrast.
  4. WebAIM: Contrast Checker — a quick tool for checking any foreground and background pair.
  5. Chrome for Developers: Make your website more readable — how to use the DevTools contrast tools.
Share :

Related Posts

Ascenders, Descenders, and Baselines: The Anatomy of a Letterform

Ascenders, Descenders, and Baselines: The Anatomy of a Letterform

You align an icon next to a button label and it looks a pixel or two too high, no matter how you adjust vertical-align. You set overflow: hidden

Continue Reading
Are Google Fonts GDPR-Compliant?

Are Google Fonts GDPR-Compliant?

In late 2022, thousands of small business owners in Germany and Austria opened letters demanding a few hundred euros in "damages" because their websi

Continue Reading
How to Audit Web Font Performance with Lighthouse?

How to Audit Web Font Performance with Lighthouse?

A client sends you a screenshot of their PageSpeed Insights report: performance score 61, LCP 3.9 seconds, and a vague list of warnings. They want to

Continue Reading