a11y teacher edition W3C WCAG 2.2 & WCAG 3.0 draft reference
Plain English Accessibility Hub

Translating W3C Standards for Designers, Developers, QA & Product teams

Contrast lab

WCAG 2 contrast ratio and APCA, side by side

Pick any two colours, a text size, a weight and, if you like, a patterned background, and see how WCAG 2.2's contrast ratio and APCA score the same pair. Further down, a heading changes colour with its own rendered size, and both measures follow it as it scales.

Compare a colour pair

You can also type a hex value in the field next to it.

The quick brown fox jumps over the lazy dog.

WCAG 2 contrast ratio

โ€”

โ€”

  • โ€” 1.4.3 Contrast (Minimum), AA
  • โ€” 1.4.6 Contrast (Enhanced), AAA

APCA lightness contrast

โ€”

โ€”

  • โ€” Simplified guide level

โ€”

Try a pair

Contrast that follows text size

The heading below takes its size from the window. Its colours are worked out from that rendered size: at 64px it is a soft tone on a tinted panel, and as it shrinks the text moves to full black (white in dark mode) and the panel to white (black). Resize the window, or set a size by hand.

The smaller I am, the more contrast I get.
Rendered size
โ€”
โ€”
Colours
โ€”
text on background
WCAG 2 ratio
โ€”
โ€”
APCA Lc
โ€”
โ€”

The same rule at fixed sizes

  • Aa

    16px

  • Aa

    18px

  • Aa

    24px

  • Aa

    32px

  • Aa

    40px

  • Aa

    48px

  • Aa

    56px

  • Aa

    64px

How it works

tan(atan2(1em, 1px)) turns an element's rendered font size into a plain number of CSS pixels, which colour functions can use. The text colour sits on an inner element because Chromium resolves em inside the color property against the parent's font size; the inner element inherits the specimen's size, so it works either way.

.specimen {
  --s: tan(atan2(1em, 1px));                /* rendered size in px */
  --t: clamp(0, (var(--s) - 18) / 46, 1);   /* 0 at 18px, 1 at 64px */
  background: oklch(calc(1 - 0.09 * var(--t)) calc(0.035 * var(--t)) 250);
}
.specimen > .ink {
  color: oklch(calc(0.58 * var(--t)) calc(0.09 * var(--t)) 262);
}

Where this site uses it

Headings on this site that use the default text colour shift toward the accent colour as they get larger, from 24px up to 44px, and keep full contrast at smaller sizes. Both ends of that range measure at least 4.5:1 on every surface, in light and dark mode. The Heading tint slider under Reading options turns it down or off, and it switches off by itself when your system asks for more contrast or when you pick one of the panel's colour themes.

Method