DEV Community

Cover image for Your color palette probably fails accessibility. Here's how to check it in 30 seconds
Avishek Dhimal
Avishek Dhimal

Posted on

Your color palette probably fails accessibility. Here's how to check it in 30 seconds

Here's an uncomfortable stat: most color palettes that look great fail the most basic accessibility test — text contrast.

I learned this the hard way. I built a landing page with a palette I loved: soft coral text on a warm cream background. Beautiful in a screenshot. Then someone told me they literally couldn't read my hero heading on their phone in daylight.

The palette wasn't the problem. The pairing was.

The 30-second check

Text readability is measured by contrast ratio — how different your text color is from the background behind it. The WCAG standard is simple:

  • 4.5:1 minimum for normal body text (AA)
  • 7:1 for the stricter AAA level
  • 3:1 for large text (24px+)

Black on white is 21:1 — maximum contrast. My coral-on-cream disaster? About 2.1:1. Nobody with less-than-perfect vision (or a sunny day) had a chance.

The fastest way to check: any contrast checker tool, or the one built into Chrome DevTools — inspect a text element, click the color swatch in Styles, and the contrast ratio is right there with AA/AAA badges.

The formula, if you're curious

The math behind it is relative luminance:

function luminance(r, g, b) {
  const a = [r, g, b].map(v => {
    v /= 255;
    return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
  });
  return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}

function contrast(rgb1, rgb2) {
  const l1 = luminance(...rgb1);
  const l2 = luminance(...rgb2);
  return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
}

contrast([255, 255, 255], [17, 17, 17]); // ≈ 18.88
Enter fullscreen mode Exit fullscreen mode

That's the exact formula Chrome, Lighthouse, and every checker uses. No magic.

The workflow fix

The real lesson wasn't "run a checker at the end" — it was choosing pairings up front. Now when I pick a palette, I decide immediately: which color is text, which is background, which are decoration-only. The vivid middle tones that fail contrast? They become borders, accents, and illustrations — never words.

A pattern that always works:

:root {
  --bg: /* your lightest color */;
  --text: /* your darkest color */;
  --accent: /* the vivid one — buttons, badges, never body text */;
}
Enter fullscreen mode Exit fullscreen mode

If your lightest-on-darkest doesn't hit 4.5:1, the palette needs a darker dark or a lighter light. Adjust lightness, not hue — the palette keeps its character.

I ended up building this check into PaletteCSS, a free palette tool I work on — every palette page shows a WCAG contrast table for all color pairings, so you can see which combos are safe for text before you commit. No signup, if you want to sanity-check your current palette.

TL;DR

  1. Body text needs 4.5:1 contrast minimum
  2. Check in DevTools — it's built in
  3. Assign roles when you pick colors: text, background, accent
  4. Vivid mid-tones are for decoration, not words

Your design isn't done when it looks good. It's done when everyone can read it.

Top comments (0)