Skip to content

Field notes

Why a color blind friendly palette cannot carry your error state

Ready palettes, copyable hex values, and the contrast ratio for every pair — including the numbers that explain why a palette which passes every check is the one least able to tell your states apart.

· 10 min read · Guide · By Mike Koval

# Why a colour-blind-friendly palette cannot carry your error state

Your designer sent the palette back with every swatch darkened until each one cleared 4.5:1 against white. Darkening them is what made your five states identical. Error, warning, success, information, neutral — five colours, five contrast passes, and in the browser's greyscale emulation they are the same grey.

That is arithmetic rather than taste. Contrast against white is a measure of how dark a colour is, so pushing five colours dark enough to pass pushes all five into the same narrow band of dark. There is nowhere else for them to go. The five in the table below are ordinary, defensible choices; measured against each other rather than against the page, the furthest apart any two of them get is 1.14:1, and error and success come out at 1.00:1.

What that costs you is not a fine. It is the enquiry form that comes back with a red border and no message. It is the person who cannot tell that border from the grey ones, fills the form in twice, and leaves. And it is a monthly enquiry count that drops by an amount nobody attributes to a palette.

Five status colours that all pass contrast land within 1.14:1 of each other

These are ready to paste into your tokens file. Every ratio below uses the WCAG 2.2 contrast formula (opens in a new window) and can be checked from the hex beside it.

RoleInkSurface tintInk on whiteInk on its tintTint on whiteInk in greyscale
error#B3261E#FDECEA6.54:15.72:11.14:1#5D5D5D
warning#8A5300#FDF3E26.33:15.76:11.10:1#606060
success#036B52#E7F4F06.50:15.76:11.13:1#5E5E5E
information#0B57A4#E8F0FB7.21:16.28:11.15:1#575757
neutral#55595E#EFF1F37.05:16.23:11.13:1#595959

Read the last column before the first. Five hues, and in greyscale they are #5D5D5D, #606060, #5E5E5E, #575757 and #595959 — a spread of nine values out of 256. Whatever separates these colours for you, it is not available to a reader who has lost the channel that carries it. The ceiling is what does it: clearing 4.5:1 against white caps a colour's relative luminance at 0.1833, and all five are pressed against that cap.

The tint column has the same problem one layer down. If the pale background is what marks where the alert begins, that boundary is running at between 1.10:1 and 1.15:1 against the page, and SC 1.4.11 Non-text Contrast (opens in a new window) (Level AA, introduced in WCAG 2.1) asks for 3:1 against adjacent colours. The tint is a surface. It is not a boundary and it is not a signal.

[GATE A — 1 · BLOCKED] The occasion from Mike's own work belongs here: one specific time a status palette came back passing every contrast check and failing in front of somebody. Who sent it, what the five roles were, and what he did first. Do not draft around this.

Greyscale is the test you already have

Chrome DevTools carries an "Emulate vision deficiencies" control in its Rendering tab, and one of its options is achromatopsia. Turn it on, load your form in its error state, and look at whether you can still tell what happened.

That test is not a proxy for the standard. It is close to the standard's actual text. SC 1.4.1 Use of Color (opens in a new window) is Level A — the lowest bar the guidelines have — and it reads: "Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element." A Level A failure is not a refinement you schedule for next quarter. It is the floor.

So the five colours above are not a failed palette. They are a palette doing the only job a palette can do, which is to be legible. The state itself has to be carried by something that survives the loss of hue: the word, an icon with a distinct silhouette, a position, a border weight. Give the error field a message that says what is wrong, and the colour becomes reinforcement rather than the carrier.

What the simulations do not tell you

The greyscale column above, and any deuteranopia, protanopia or tritanopia view you generate, are models. They approximate dichromacy at full severity. Most people with a colour vision deficiency are anomalous trichromats rather than dichromats, which means they see a reduced separation rather than none, and the amount varies by person.

So a simulation is a way of finding failures, not a way of confirming success. It has the same shape as every other automated accessibility check: useful for what it catches, silent about the rest.

The contrast formula is a model too. (L1 + 0.05) / (L2 + 0.05) is a ratio of reflected light, not a measurement of what any particular person perceives. It is the one the standard and the law point at, which is why every number here uses it.

The prevalence figure has the same problem. The US National Eye Institute puts it at "about 1 in 12 men" (page last updated November 5 2025) and gives no figure for women on that page. The commonly repeated 0.5% for women is not on it. If a number is going into your business case, take the one you can point at.

The palettes that are famous for this were drawn for figures in journals, not for your form validation

The eight-colour set almost everyone reaches for comes from Okabe and Ito's Color Universal Design (opens in a new window), last modified in 2008. Both authors are protanopes. It does what it was built to do, which is to keep categories apart in a scientific figure. The hex values below are the ones that circulate; the ratios are computed from them.

NameHexOn whiteOn #15171AIn greyscale
black#00000021.00:11.17:1#000000
orange#E69F002.25:17.97:1#ADADAD
sky blue#56B4E92.31:17.78:1#ABABAB
bluish green#009E733.42:15.25:1#8B8B8B
yellow#F0E4421.32:113.58:1#E0E0E0
blue#0072B25.19:13.46:1#6D6D6D
vermilion#D55E003.87:14.64:1#828282
reddish purple#CC79A73.06:15.87:1#939393

Two of the eight clear 4.5:1 against white. Set text in these hexes and six of your eight miss the 4.5:1 that SC 1.4.3 (opens in a new window) asks for normal text — and three of them, orange, sky blue and yellow, miss even the 3:1 it allows for large.

The adjacency numbers are the sharper problem. Orange and sky blue sit at 1.02:1 against each other, bluish green and vermilion at 1.13:1, bluish green and reddish purple at 1.12:1. Put any of those pairs side by side as stacked bar segments, or as a legend swatch against the series it labels, and you are now arguing about 1.4.11, which asks 3:1 against adjacent colours for a part of a graphic required to understand the content. In a journal figure with a printed legend beside it, that never mattered. In your dashboard it does.

The Okabe-Ito set is not wrong and it is not careless. It was solved for hue separation under dichromacy, and against that brief it holds up. It was never solved for text contrast against a page, and nobody said it was.

A link colour that clears the page can still fail the paragraph it sits in

The same failure has a second address on your site, and it is the one nobody checks. Take #0B57A4 for links against body text at #15171A on white. The link is at 7.21:1 against the page, which passes. Against the ink it sits in, it is at 2.49:1 — and the ink is what the reader is comparing it to.

W3C's Understanding document for 1.4.1 says a lightness difference "counts as an additional visual distinction, as long as the difference in relative luminance between the colors leads to a contrast ratio of 3:1 or greater." That is advice on how to satisfy the criterion rather than a criterion of its own, and it leaves you two routes and no third:

  • Underline links in body copy, which settles it outright and needs no arithmetic.
  • Or move the link colour into the band where it clears 3:1 against the surrounding ink, which costs you contrast against the page in exchange.

Underlining is the cheaper one almost every time, and it is the one that also survives the reader who has turned your stylesheet off.

[GATE A — 2 · BLOCKED] Something a client, developer or designer actually said when told the link colour had to change or the underline had to come back. Their words, their job, and whether the sentence can be cleared for quotation (SVC-016). Do not paraphrase a quote into existence.

One focus ring for a light page and a dark footer has almost nowhere to live

One accent colour has to work as a focus ring on your white pages and on your near-black footer, and the band it can live in is narrower than it looks. To clear 3:1 against white, a colour's relative luminance must sit at or below 0.3000. To clear 3:1 against a near-black surface such as #15171A, it must sit at or above 0.1254. Ask it to double as readable text on white and the ceiling drops to 0.1833.

That leaves a band from 0.1254 to 0.1833 — under six points of a hundred — inside which a single colour works as a focus ring on your light pages and on your dark footer, and as a link colour against body ink, without being reassigned per surface.

HexOn whiteOn #15171ARelative luminance
#0072B25.19:13.46:10.1525
#6E56CF5.39:13.33:10.1448
#0080604.93:13.64:10.1628
#7676764.54:13.95:10.1812
#00838F4.52:13.97:10.1822

#0072B2 is the Okabe-Ito blue, and it lands at 0.1525, near the middle of the band. That is a coincidence worth using rather than a principle.

The usual instinct is to reach for the darkest accessible version of the brand colour, which is why so many focus rings measure fine on the page and disappear on the footer. #0B57A4 is a typical result: 7.21:1 on white, 2.49:1 on #15171A. It passes the check somebody ran and fails the surface nobody tested.

There is a criterion aimed squarely at this and you are probably not bound by it. SC 2.4.13 Focus Appearance (opens in a new window) arrived in WCAG 2.2 at Level AAA, and it asks for something the band above does not give you: an indicator at least as large as a two-pixel perimeter of the component, with 3:1 measured between the same pixels focused and unfocused rather than against the surface behind them. At AAA it is almost certainly not your obligation. It is a good description of a ring somebody can actually see.

[GATE A — 3 · BLOCKED] A decision Mike made on a real palette and what it cost — the option he ruled out, and what he gave up by ruling it out. Surface-aware tokens against one band colour is the likely shape, but the specifics have to be his.

What I will not do to your brand colours

I will not recolour a brand to solve this. Swapping hues does not repair a state that has no non-colour carrier; it produces a different set of colours with the same gap sitting inside it.

And a safe palette is not an accessible site. If somebody has sold you a palette swap as AODA remediation, that is a small part of one Level A criterion out of dozens, and the rest of the site is untouched. That is not the work, and I would say so before you bought it.

What I will do is take the colours you already own, publish the ratios so the argument stops being a matter of taste, and find the non-colour carrier for every state that currently has none. That is a smaller job than a rebrand, and it produces something you can show somebody.

Two things you can check before the end of the day. Open your form in its error state with greyscale emulation on, and see whether you can tell what went wrong. Then tab to the footer and look at whether the focus ring is still there.

If either one gives you an answer you do not like, the question underneath it is how many other criteria the site is in that position on, which is what an audit is for.

Palette values and contrast ratios computed September 2026 against WCAG 2.2.