Why it matters
Contrast checkers test one pair at a time, but a palette is a set of promises: the muted grey is used on the page and on cards, the link colour sits on light and dark sections, white text goes on the brand button. Fix one pair by hand and you can break another. And WCAG 2's ratio and APCA, the perceptual method being developed for WCAG 3, disagree most on exactly the mid-tones brands use, so a colour can pass one and fail the other.
This optimiser takes your palette and the pairs your design actually uses, checks each with WCAG 2 and APCA Lc against body, large-text or UI targets, and then fixes the failures. It moves only OKLCH lightness, so hue stays the same and the colour still looks like itself, and it picks the smallest change that makes all of that colour's pairs pass together. Locked colours never move. When no single lightness can work, typically one link colour used as text on both a light and a dark background, it says so and suggests splitting the token, instead of producing a colour that passes nothing well.
How it works
- InputColours and the pairs you use
- In your browserWCAG 2 and APCA per pair; lightness nudged in OKLCH
- OutputA passing palette as CSS
Where it fits in a designer's workflow
- Plan
- Design
- Build
- Test
- Launch
By the numbers
Show the numbers as a table
| Pair | Use | Lc before | Lc after | WCAG before | WCAG after | Passes |
|---|---|---|---|---|---|---|
| ink on paper | body | 81 | 81 | 6.87 | 6.87 | yes |
| muted on paper | body | 52 | 75 | 2.81 | 5.55 | yes |
| link on paper | body | 62 | 50 | 3.7 | 2.7 | no |
| brand on paper | ui | 47 | 54 | 2.52 | 3.01 | yes |
| brand-ink on brand | large | 57 | 64 | 2.7 | 3.22 | yes |
| paper on night | body | 101 | 101 | 16.07 | 16.07 | yes |
| link on night | body | 34 | 45 | 4.34 | 5.94 | no |
How to use it
- List the palette, adding lock to brand colours that can't change.
- List each text-on-background pair and what it's for.
- Pick the standard to meet.
- Review the changes and previews, then copy the CSS.
FAQ
What's the difference between WCAG 2 and APCA?
WCAG 2 uses a luminance ratio (4.5:1 for body text). APCA, from the WCAG 3 work, models perceived lightness contrast and polarity, giving an Lc value; it's stricter on dark-on-mid colours and more lenient on light text on dark. Meeting both is the safest choice today.
Which APCA targets does it use?
The simplified Bronze levels: Lc 75 for body text, Lc 60 for large or bold text, Lc 45 for UI elements and icons. Fluent text at small sizes may need Lc 90.
Why only change lightness?
Lightness is what contrast depends on. Changing it in OKLCH keeps the hue, so an orange stays orange. Chroma is lowered only when the lighter or darker version can't be shown in sRGB.
What does 'lock' do?
A locked colour is never changed, so brand colours and backgrounds stay exact and the others adapt to them.
Why can't some pairs be fixed?
When one colour is text on both light and dark backgrounds, darkening it for one makes it worse on the other. Use two tokens, such as link and link-on-dark.