Designing for the 300 Million People with Color Vision Deficiency
One in twelve men and one in two hundred women have some form of color vision deficiency. That works out to about 300 million people worldwide. In a product used by ten thousand people, roughly 700 of them will see your color choices differently than you intend. In a B2B SaaS dashboard used by thirty engineers at one customer, that is probably three of them. This post is about catching the failures before those users do.
The most common failure I see
Status badges. "Green = success, red = error" is the universal pattern. To a user with deuteranopia (the most common type, affecting about 6% of men), both badges are shades of muddy yellow-brown. They are visually indistinguishable.
I caught this in my own dashboard during a user test with a friend who has deuteranopia. We had a table of API requests with red rows for errors and green for success. He could not tell them apart. The dashboard had been "working" for months in front of every other developer on my team.
The fix is small. Add an icon next to the color: ✓ for success, ✗ for error. Add a text label: "Success" / "Error". Now the color is decorative, and the meaning is conveyed redundantly. This is the central principle of accessible color use: color is never the only encoding.
The four types of CVD
Color vision deficiency comes in four flavors, each missing or shifted in different cones:
- Protanopia (~1% of men): missing L-cones, so red looks dark. Red and green are confused; orange and yellow look similar.
- Deuteranopia (~1% of men) and protanomaly + deuteranomaly (the milder forms, ~5% combined): missing or shifted M-cones. The most common type. Red/green confusion.
- Tritanopia (~0.001%): missing S-cones. Blue/yellow confusion. Much rarer.
- Achromatopsia (~0.003%): no color vision at all, everything is grayscale.
Plus the milder partial versions: protanomaly, deuteranomaly, tritanomaly. These are more common than full -opia and harder to test because the affected person sees most things normally with just some specific confusions.
You can simulate all four using the color blindness simulator on this site. Upload your design, see how it looks.
Five patterns that work
1. Icon + text + color
For every status, alert, or category that uses color: pair it with an icon and a text label. The icon and text carry the meaning; the color is decoration.
// Bad <span class="badge red">DOWN</span> // Better <span class="badge danger">✗ DOWN</span>
2. Choose palettes designed for accessibility
The Viridis, Cividis, and Inferno color palettes were designed to be perceptually uniform across all forms of color vision. They are the standard for scientific data visualization in 2026. ColorBrewer (older but still good) offers palettes specifically tested for CVD.
Avoid the classic red-yellow-green or rainbow palette. They look great to trichromats and useless to everyone else.
3. Use shape, position, and pattern as secondary encodings
Line charts: differentiate series with line style (solid, dashed, dotted) as well as color. Scatter plots: use shape (circle, square, triangle) as well as color. Bar charts: position is already an encoding, so color is genuinely decorative, so make it pretty rather than meaningful.
4. Test contrast separately from color choice
Color blindness and low contrast are independent problems. A red-on-green button might fail for CVD users and also fail WCAG contrast ratios. Use the contrast checker against luminance, then test with the color blindness simulator. Both checks are necessary.
5. Use OKLCH for consistent perceived brightness
HSL has uneven perceived brightness across hues. OKLCH (covered in my CSS color post) gives you "Lightness 70" colors that all appear equally bright to the human eye. This means a "status badge" recipe like oklch(60% 0.2 H) produces consistent-feeling badges across hues, which also helps CVD users because the absolute brightness becomes a reliable signal.
Specific high-stakes patterns
Form validation
A red border on an invalid field is not enough. Add an icon (⚠️) and a text message ("Please enter a valid email"). The icon survives CVD; the text survives screen readers; the color is decoration.
Charts and graphs
Worst-case: a multi-line chart with a small legend in the corner mapping color to series name. CVD users cannot match the lines to the legend. Better: label each line directly on the chart, near its rightmost endpoint. Sometimes use different line styles (solid, dashed, dotted).
Heatmaps
Sequential heatmaps (light-to-dark of one hue) survive CVD because the lightness gradient is preserved. Diverging heatmaps (red-to-green) do not. Use sequential palettes (Viridis, single-hue) for CVD safety.
Required field markers
A red asterisk is invisible to ~3% of users. Use the word "required" or a red asterisk plus the word.
A note on darkmode
Dark themes do not fix CVD problems. They sometimes make them worse because high-contrast dark backgrounds can saturate the foreground colors more, making confusions sharper. Test both light and dark themes with the simulator.
What I do now
Every time I add a new color-coded element to a UI, I drop a screenshot into the simulator and look at all four simulation panels. If any of them make the encoding ambiguous, I add an icon or text label. This adds about 30 seconds per design and prevents the kind of "wait, success and error look the same to me" moment that I caught only by accident.