Start a project

Tool 34 of 194 · Colour

APCA & WCAG Palette Optimiser

List your colours and which ones sit on which, and get a palette where every pair passes WCAG 2, APCA or both, with hue and locked brand colours kept.

APCA & WCAG Palette Optimiser at a glanceIllustration: 1, Palette; 2, processed in your browser; 3, Every pair passes.APCA & WCAG Palette OptimiserAa 4.5:11Palette3Every pair passes2In yourbrowser
1 Palette 2 processed on your device 3 Every pair passes

APCA & WCAG Palette Optimiser

Your palette and where each colour is used

    Pairs, before and after

    PairUseBeforeAfterResult

    Colours changed

    ColourBeforeAfterLightnessΔELocked

    APCA Lc per pair

    Every colour on every other

    Green passes for body text, amber for large text only, at the standard you picked.

    Export

    CSS variables
    JSON report

    01

    What it does

    Checks a palette's text and background pairs with WCAG 2 and APCA, then fixes the failures by moving OKLCH lightness as little as possible.

    • WCAG 2 AA or AAA ratios and APCA Lc, or both at once
    • Body, large and UI targets per pair
    • Lock brand colours so only the others move
    • Lightness-only fixes in OKLCH: hue kept, chroma kept where sRGB allows

    02

    Private by design

    Everything happens in your browser. Nothing you type, paste or upload is sent anywhere, and it keeps working offline once the page has loaded.

    03

    What you get

    Before and after contrast per pair, the changed colours, a full matrix and CSS, with a Copy and a Download button on every result.

    • Colour
    • Accessibility
    • Contrast
    • APCA
    • OKLCH

    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

    1. InputColours and the pairs you use
    2. In your browserWCAG 2 and APCA per pair; lightness nudged in OKLCH
    3. OutputA passing palette as CSS

    Where it fits in a designer's workflow

    1. Plan
    2. Design
    3. Build
    4. Test
    5. Launch
    Fixing a brand palette that fails contrast without changing its character.

    By the numbers

    APCA Lc per pair in the sample palette, after optimisingink on paper: Lc 81; muted on paper: Lc 75 (was 52); link on paper: Lc 50 (was 62); brand on paper: Lc 54 (was 47); brand-ink on brand: Lc 64 (was 57); paper on night: Lc 101; link on night: Lc 45 (was 34)Body Lc 75ink on paperLc 81muted on paperLc 75 (was 52)link on paperLc 50 (was 62)brand on paperLc 54 (was 47)brand-ink on brandLc 64 (was 57)paper on nightLc 101link on nightLc 45 (was 34)
    Computed by this tool from its sample: 7 pairs, 3 colours moved in OKLCH lightness only. The link colour is text on both the light paper and the dark night background, so no single lightness can reach Lc 75 on both, and the tool says to split it instead of picking a colour that fails both. Source: W3C: WCAG 2.2, 1.4.3 Contrast (Minimum); APCA: Bronze simple mode guidelines.
    Show the numbers as a table
    PairUseLc beforeLc afterWCAG beforeWCAG afterPasses
    ink on paperbody81816.876.87yes
    muted on paperbody52752.815.55yes
    link on paperbody62503.72.7no
    brand on paperui47542.523.01yes
    brand-ink on brandlarge57642.73.22yes
    paper on nightbody10110116.0716.07yes
    link on nightbody34454.345.94no

    How to use it

    1. List the palette, adding lock to brand colours that can't change.
    2. List each text-on-background pair and what it's for.
    3. Pick the standard to meet.
    4. 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.

    Work with me

    Want a site that gets these right?

    I build fast, accessible websites and web apps that pass these checks from day one. Tell me about your project and I'll reply personally with honest next steps.

    All developer tools · Back to leej.uk