Experiment · 2026

Contrast Checker

Live
  • Accessibility
  • Colour
  • Tool

WCAG contrast ratio between any two colours, computed live. Built because I kept opening a web tool for a formula that is four lines long.

Contrast checker · WCAG 2.25.48:1
5.48: 1
AA normalPass
AA largePass
AAA normalFail
AAA largePass

Large text, 24px and up

Normal body text at fourteen pixels. This is the size that fails first, and it is the size most of your interface is actually set in.

Contrast ratio 5.48 to 1

01 — WhyWhat made this worth building

Every dark theme I build has one text colour that fails AA at small sizes and passes at large, and I never remember which. Having the maths inline means I check it while I am picking the colour instead of during an audit six weeks later.

02 — NotesHow it works

The contrast ratio is `(L1 + 0.05) / (L2 + 0.05)` where L is relative luminance and L1 is the lighter of the two. The 0.05 term models ambient screen reflection — it is why pure black on pure white tops out at 21:1 rather than infinity.

ts
function luminance({ r, g, b }: RGB) {
  const channel = (v: number) => {
    const s = v / 255;
    // the gamma curve is piecewise: linear near zero, power elsewhere
    return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
  };
  return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
}

function ratio(a: RGB, b: RGB) {
  const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
  return (hi + 0.05) / (lo + 0.05);
}

The thresholds: 4.5:1 for normal text, 3:1 for large text (18.66px bold or 24px regular) and for UI component boundaries. AAA raises those to 7:1 and 4.5:1. Note that WCAG 2 contrast is known to be a poor model for dark themes — APCA is the intended successor. This tool implements WCAG 2 because that is what audits still test against.