Short answer: contrast comes from lightness, so keep text and background apart in it
Keep text readable when you swap a palette: why a dark hero stays dark
To make a color palette accessible, keep every color that carries text far apart in lightness from the color it sits on: contrast comes almost entirely from lightness, and WCAG asks for 4.5:1 for normal text and 3:1 for large text and interface parts. Recolor (recolor.page) applies this when it swaps a page's palette: lightness shifts beyond 0.35 in OKLCH are held back, so a dark hero stays dark and its white text readable.
Last updated
src/shared/mapping.ts), checked October 8, 2026| What | Minimum | Source |
|---|---|---|
| Normal text | 4.5:1 (AA), 7:1 (AAA) | WCAG 2.2, 1.4.3 and 1.4.6 |
| Large text: 18 pt, or 14 pt bold | 3:1 (AA), 4.5:1 (AAA) | WCAG 2.2, 1.4.3 and 1.4.6 |
| Interface parts and graphics | 3:1 against adjacent colors | WCAG 2.2, 1.4.11 |
| Recolor's lightness guard | Full shift up to 0.35, none from 0.6 | Recolor's mapping, OKLCH lightness |
| Recolor's text check | As much as the page had, up to 4.5:1 (3:1 large) | Recolor's mapping |
Contrast is mostly lightness
WCAG's contrast ratio compares the relative luminance of two colors, a weighted sum of their red, green and blue
light. Hue matters far less than lightness. Three colors with the same OKLCH lightness (55%) and chroma but a red, a green and
a blue hue, #ad524d, #3e8343, #4f6eb7, give 5.13:1, 4.63:1, 4.95:1
against white. Change the lightness instead and the ratio moves a lot.
That is why an accessible palette is planned in lightness, and why every page in the palette gallery lists each color's contrast with black and white text: a dark color or two for text, light ones for backgrounds, and mid-tones for buttons and accents that are checked against whatever sits on them. Black or white text on a color works out where the switch from black to white text lies.
Why HSL lightness misleads
HSL gives pure yellow and pure blue the same lightness, 50%. Their contrast with white is 1.07:1 for yellow and 8.59:1 for blue. OKLCH puts them at 97% and 45% lightness, which is what the eye sees. A palette built on OKLCH lightness steps keeps its contrast when the hues change; one built on HSL steps does not. What OKLCH is covers the color space itself.
What happens to a dark hero under a pale swatch
Say a page has a navy hero, #1d3557, with white text on it (12.36:1), and the new palette's
swatch for it is a pale wheat, #f4dd9f. Moving the navy 70% of the way to the
swatch in every channel, lightness included, gives #bba66d, and the white text on it drops to
2.39:1.
Recolor moves the hue and the chroma that way, but the lightness only as far as its guard allows. The shift here is
0.57 in OKLCH lightness, between 0.35 and 0.6, so only 10% of it passes, and the hero becomes #4f3d00, a dark olive brown in
the swatch's hue, with white text at 10.50:1.
The page reads like the same design in a new palette instead of a broken one. Strength, neutral tint and
overrides has the full rule, including the check that gives text back lightness where a palette
would push it below what the page had.
A checklist for an accessible palette
- Include at least one color dark enough for body text on your light backgrounds, and one light enough for text on your dark sections.
- Check every text pair you will use, not each color alone: body text, links in body text, button labels, text on the hero and on badges.
- Keep buttons, inputs and focus rings at 3:1 against what surrounds them.
- Do not let color alone carry meaning, such as red for an error with no icon or text (WCAG 1.4.1).
- Look at it on the real page: a pair that passes in a swatch strip can still sit on a photo or a gradient.
Recolor checks up to 3,000 text elements of a loaded page and keeps the 150 heaviest text and background pairs readable as palettes change, which makes it a quick way to test a palette on your own site.
Common questions
Is 4.5:1 enough for body text?
Yes, for WCAG level AA. Level AAA asks for 7:1 for normal text and 4.5:1 for large text.
Can a different hue make low-contrast text readable?
No. At the same lightness, hue changes the ratio only a little; change the lightness of the text or of its background.
Does an accessible palette need pure black or white?
No. Near-black and near-white colors from the palette work, as long as each text pair reaches 4.5:1.
Does WCAG's contrast rule apply to buttons?
Yes, twice: the label is text and needs 4.5:1 against the button, and the button's edge needs 3:1 against the page when it is what shows the button.
Does Recolor make every page accessible?
No. It keeps text at least as readable as the page had it, up to 4.5:1, while it changes the palette; a page that failed before can still fail.
Can I turn Recolor's lightness guard off?
No, but Strength sets how far colors move: at 0% the page keeps its own lightness and only takes the palette's hues.