Skip to content

Guide

Color contrast for accessibility: WCAG 2.1, APCA, and what to actually ship

WCAG 4.5:1 is the legal floor. It's also a flawed formula. Here's the modern picture.

WCAG 2.1 requires 4.5:1 contrast ratio for regular body text and 3:1for large text (18pt+ regular or 14pt+ bold). The formula is the de-facto legal standard in the US (ADA-relevant), EU (EAA), and most of the world. It also has well-documented flaws that have spawned a replacement (APCA) which didn’t make WCAG 2.2. This guide explains the practical picture today.

The WCAG 2.x contrast formula

Defined in WCAG 2.0 (2008) and unchanged through 2.2:

contrast = (L_light + 0.05) / (L_dark + 0.05)
where L = relative luminance (0-1) of each colour, computed in linear-light sRGB

Results range from 1:1 (identical colours) to 21:1 (pure white on pure black).

WCAG thresholds (for AA compliance, the standard target):

  • 4.5:1 — body text, icons, form controls.
  • 3:1 — large text (≥ 18pt or ≥ 14pt bold), UI components (button borders, focus indicators).
  • AAA targets are stricter: 7:1 body, 4.5:1 large. Required only in some specific contexts (legal text, government).

Where the formula is wrong

Three documented problems:

  1. Mid-tone insensitivity. The formula gives equal contrast scores to mid-tone pairs (e.g., grey on grey) that look very different in actual perception. A 4.5:1 pair of mid-greys can be visually weaker than a 3:1 pair of black on light grey.
  2. Hue-blind.Equal-luminance hues (red and green at the same brightness) score 1:1 contrast, but dichromat users may discriminate them poorly anyway. The formula can’t detect colour-blindness issues.
  3. Font weight ignored.Thin fonts need more contrast than bold fonts at the same size; WCAG gives no credit for weight beyond the binary “large text” threshold.

APCA: the replacement that didn’t make WCAG 2.2

APCA (Accessible Perceptual Contrast Algorithm) is the proposed-and-rejected next-generation contrast metric. Developed by Andrew Somers for WCAG 3.0 working draft. It accounts for the issues above and is dramatically more accurate against actual user-study data.

APCA scores range −108 to +106. Positive means dark text on light background; negative means the reverse. Thresholds:

  • Lc 75 — body text (replaces WCAG’s 4.5:1).
  • Lc 60 — large text or headlines (replaces 3:1).
  • Lc 45 — non-content text (decorative, copyright lines).

APCA gives different thresholds per direction (light-on-dark vs dark-on-light) because human eyes process the two cases differently. WCAG’s symmetric formula misses this.

What to use in 2026

Two-track approach:

  1. Pass WCAG 2.1 AA at minimum.It’s the legal standard. Use the standard ratio formula, target 4.5:1 body / 3:1 large. Tools: npm i wcag-contrastfor programmatic, browser DevTools (Chrome and Firefox both report contrast on hover) for ad-hoc.
  2. Use APCA as a sanity check. When WCAG passes but the result looks subjectively weak, APCA usually flags it. APCA is available as apca-w3(npm) and in dedicated tools (Atmos, Stark plugins).

Both metrics agree on the obvious cases (black text on white is fine; pale grey on white is not). They diverge on the mid-tone and large-text edge cases — exactly where modern design trends like to live.

Concrete recommendations

  • Body text: targeting #1a1a1a(dark grey) on white gives ~17:1 — pleasant, clearly legible. Pure black on white (21:1) can feel harsh; deliberate near-black is fine.
  • Disabled / placeholder text:WCAG exempts “inactive UI components” from the 4.5:1 rule, but users still need to read placeholders. Target 3:1 minimum.
  • Buttons:button text vs button background must hit 4.5:1. Button border vs page background must hit 3:1 (for the “non-text contrast” rule).
  • Focus indicators: the focus outline must hit 3:1 against the adjacent background. This is the rule that breaks the most when designers remove default browser focus outlines.
  • Dark mode:the WCAG formula is symmetric; numbers translate. But APCA is asymmetric — dark mode tends to need slightly different design tokens than light mode for the same perceived quality. Don’t just invert colours.

What to skip

  • Don’t use contrast as the sole signal for state. Error states need contrast andanother cue (an icon, text). Colour-blind users may not distinguish red errors from green successes even at high contrast.
  • Don’t target AAA reflexively.WCAG’s own guidance says AAA is “not recommended as a general policy for entire sites” — it’s for specific contexts. AA is the design ceiling for most products.
  • Don’t trust auto-generated colour ramps uncritically.An OKLCH ramp with even perceptual steps doesn’t automatically pass WCAG. Verify each adjacent pair.

The pragmatic workflow

At design time: use the WCAG contrast checker in your design tool (Figma, Sketch, Adobe XD all have plugins). Hit 4.5:1 / 3:1 minimums.

At code time: lint your design tokens against WCAG withwcag-contrast or similar. Fail CI on regressions.

At QA time: real screen-reader and keyboard-navigation testing. Contrast is a small slice of accessibility; the keyboard and screen-reader paths are where most a11y bugs actually live.

Sources: W3C WCAG 2.1 (2018) and WCAG 2.2 (2023); WCAG 3.0 Working Draft (2024); Andrew Somers, APCA-W3 documentation and supporting user studies.

Related

Published May 16, 2026