Color Accessibility Design: Contrast, Color Blindness & WCAG
UtilitiesRachel Kim
Color Accessibility: More Than Just "Looking Good"
About 8% of men and 0.5% of women worldwide have some form of color vision deficiency — 1 in every 12 users cannot reliably distinguish certain colors.
| Type of color vision deficiency | Prevalence | Hard to distinguish |
|---|---|---|
| Protanopia (red-blind) | 1% | Red-green |
| Deuteranopia (green-blind) | 5% | Red-green |
| Tritanopia (blue-blind) | 0.003% | Blue-yellow |
| Achromatopsia (total color blindness) | Extremely rare | All |
1. WCAG Contrast Standards
Three Levels
| Level | Normal text | Large text | UI components |
|---|---|---|---|
| AA | ≥ 4.5:1 | ≥ 3:1 | ≥ 3:1 |
| AAA | ≥ 7:1 | ≥ 4.5:1 | — |
Definition of large text: ≥ 18pt (24px) or ≥ 14pt bold (18.66px bold).
Calculating Contrast
Contrast ratio = (L1 + 0.05) / (L2 + 0.05)
L1 = relative luminance of the lighter color
L2 = relative luminance of the darker color
Relative luminance L:
For sRGB ≤ 0.03928: L = sRGB / 12.92
For sRGB > 0.03928: L = ((sRGB + 0.055) / 1.055)^2.4
sRGB = R/255, G/255, B/255 (calculated per channel)
Contrast of Common Color Pairs
| Foreground | Background | Contrast | AA normal text | AA large text |
|---|---|---|---|---|
#000000 |
#FFFFFF |
21:1 | ✅ | ✅ |
#333333 |
#FFFFFF |
12.6:1 | ✅ | ✅ |
#666666 |
#FFFFFF |
5.7:1 | ✅ | ✅ |
#767676 |
#FFFFFF |
4.5:1 | ✅ (barely) | ✅ |
#999999 |
#FFFFFF |
2.8:1 | ❌ | ❌ |
#FF0000 |
#FFFFFF |
3.99:1 | ❌ | ✅ |
#0000FF |
#FFFFFF |
8.59:1 | ✅ | ✅ |
2. Verifying Contrast with ToolsKu
Steps
- Open the Color Contrast Checker
- Enter the foreground and background colors (HEX, RGB, and HSL supported)
- Review the results:
- Contrast ratio
- WCAG AA / AAA compliance status
- Separate verdicts for normal text / large text
- Adjust the colors until they pass
3. Color Blindness Simulation
Simulating with CSS filter
/* Protanopia (red-blind) */
.protanopia { filter: url('#protanopia'); }
/* Deuteranopia (green-blind) */
.deuteranopia { filter: url('#deuteranopia'); }
/* Tritanopia (blue-blind) */
.tritanopia { filter: url('#tritanopia'); }
SVG Filter Matrices
<svg style="display:none">
<!-- Protanopia simulation matrix -->
<filter id="protanopia">
<feColorMatrix type="matrix" values="
0.567 0.433 0 0 0
0.558 0.442 0 0 0
0 0.242 0.758 0 0
0 0 0 1 0
"/>
</filter>
<!-- Deuteranopia simulation matrix -->
<filter id="deuteranopia">
<feColorMatrix type="matrix" values="
0.625 0.375 0 0 0
0.7 0.3 0 0 0
0 0.3 0.7 0 0
0 0 0 1 0
"/>
</filter>
</svg>
4. Color Blindness Adaptation Strategies
Strategy 1: Don't Rely on Color Alone to Convey Information
<!-- Wrong: distinguishing status by color only -->
<span class="status-error" style="color: red">Failed</span>
<span class="status-success" style="color: green">Success</span>
<!-- Right: color + icon -->
<span class="status-error" style="color: red">
<svg>✕</svg> Failed
</span>
<span class="status-success" style="color: green">
<svg>✓</svg> Success
</span>
Strategy 2: Use Color-Blind-Friendly Palettes
| Combinations to avoid | Alternative combinations |
|---|---|
| Red + green | Red + blue, or orange + blue |
| Light red + light green | Dark red + light green |
| Green success + red error | Blue info + orange warning |
Wong's Color-Blind-Friendly Palette
#000000 Black
#E69F00 Orange
#56B4E9 Sky blue
#009E73 Bluish green
#F0E442 Yellow
#0072B2 Blue
#D55E00 Vermilion
#CC79A7 Reddish purple
This palette stays distinguishable under every type of color vision deficiency.
Strategy 3: Use Textures/Patterns in Charts
/* Different textures for different data series */
.series-a { background-image: url('stripes.svg'); }
.series-b { background-image: url('dots.svg'); }
.series-c { background-image: url('crosshatch.svg'); }
5. Dark Mode Accessibility
Dark Mode Contrast Pitfalls
| Pitfall | Explanation | Fix |
|---|---|---|
| Pure black background with pure white text | 21:1 contrast, but causes eye strain | Use dark gray background (#1a1a2e) |
| Reduced saturation | High saturation is harsh in dark mode | Lower saturation appropriately |
| Invisible shadows | Shadows disappear on dark backgrounds | Use borders or luminance differences instead |
| Insufficient image contrast | Image detail gets lost in dark mode | Adjust with CSS filter |
Dark Mode Palette Recommendations
:root {
/* Light mode */
--bg: #ffffff;
--fg: #1a1a2e;
--muted: #6b7280;
--accent: #3b82f6;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a2e;
--fg: #e0e0e0;
--muted: #9ca3af;
--accent: #60a5fa; /* Brighter blue to maintain contrast */
}
}
6. Component-Level Accessibility Checks
Form Error Messages
<!-- Wrong: indicating an error with a red border only -->
<input style="border: 1px solid red" />
<!-- Right: border + text + aria -->
<input
style="border: 1px solid red"
aria-invalid="true"
aria-describedby="error-msg"
/>
<span id="error-msg" role="alert" style="color: #dc2626">
Please enter a valid email address
</span>
Link Contrast Against Surrounding Text
Links need sufficient contrast not only against the background, but also visual distinction from surrounding text:
/* Links are distinguished not just by color, but also by underline */
a {
color: var(--accent);
text-decoration: underline;
text-underline-offset: 2px;
}
7. Automated Testing
axe-core Integration
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
test('color accessibility', async () => {
const { container } = render(<MyComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
Lighthouse Audit
npx lighthouse https://example.com --only-categories=accessibility
CI Integration
- name: Accessibility check
run: npx pa11y https://staging.example.com
8. Best Practices Checklist
- Text contrast ≥ 4.5:1 (AA level for normal text)
- Don't rely on color alone to convey status information
- Use color-blind-friendly palettes (such as the Wong palette)
- Add textures/patterns to charts to aid differentiation
- Maintain contrast in dark mode; avoid pure black backgrounds
- Give links underlines or other non-color distinctions
- Provide text descriptions for errors, not just red styling
- Integrate automated accessibility testing into CI
#无障碍#WCAG#对比度#色盲#色彩设计