Skip to content
EN
English 简体中文 soon 日本語 soon

Learn · Guide

WCAG Contrast for Designers, Not Lawyers

The 4.5:1 and 3:1 rules explained, with palettes that stay compliant without killing the aesthetic.

The two numbers that matter

WCAG 2.1 defines contrast as a ratio between 1:1 (same color) and 21:1 (black on white). Two thresholds do almost all the work:

  • AA — 4.5:1 for normal text, 3:1 for large text (18px regular or 14px bold and up) and UI components.
  • AAA — 7:1 for normal text, 4.5:1 for large text. Stricter, used for long body copy.

Most products target AA. AAA is a bonus for reading-heavy surfaces, not a universal requirement.

Where designs actually fail

Gray-on-gray is the most common failure: a #94a3b8 label on #f1f5f9 looks "modern" but sits around 2.9:1 — fine as a large display element, failing as body text. Secondary text is where the contrast budget gets spent, so the usual fix is to keep secondary text darker (or the background lighter) rather than redesigning everything.

Strategies that keep the aesthetic

  1. Let body text go near-black. Reserve the pretty mid-gray for large headers and icons only.
  2. Test at the extremes, not the average. Light-on-dark and dark-on-light both need checking.
  3. Give hover states their own ratio. Interactive text that dims on hover can drop below 4.5:1 exactly when the user is looking at it.
  4. Don't rely on color alone. Contrast failure is often a cue for a state (error, active) that should also have an icon or underline.

Reading the numbers quickly

A ratio below 2 is decorative only. Between 2 and 3 you can use it for large display text and non-text UI, but never for body copy. Between 3 and 4.5 you are in the "large text or bold only" zone. Above 4.5 you are safe for normal text at AA, and above 7 you meet AAA for everything except the strictest cases. If you only remember one threshold, remember 4.5:1 for normal body text.

The palette checklist

When you build a new theme, run these pairs through the checker before anything ships: body text on page background, muted text on page background, text on every surface and card colour, text on every brand colour you plan to put labels on, and button labels on their button fills. Those five checks catch the overwhelming majority of real-world contrast failures, and they take about ten minutes once you have the tokens defined.

How to verify

Use ToolsKit's color contrast checker on every text/background pair in your palette: paste #HEX, rgb() or hsl() values and it returns the ratio plus PASS/FAIL for AA and AAA at normal and large sizes. Check pairs as you design, not as a pre-launch audit.