Color Accessibility Design: Contrast, Color Blindness & WCAG

Utilities

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

  1. Open the Color Contrast Checker
  2. Enter the foreground and background colors (HEX, RGB, and HSL supported)
  3. Review the results:
    • Contrast ratio
    • WCAG AA / AAA compliance status
    • Separate verdicts for normal text / large text
  4. 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>

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

  1. Text contrast ≥ 4.5:1 (AA level for normal text)
  2. Don't rely on color alone to convey status information
  3. Use color-blind-friendly palettes (such as the Wong palette)
  4. Add textures/patterns to charts to aid differentiation
  5. Maintain contrast in dark mode; avoid pure black backgrounds
  6. Give links underlines or other non-color distinctions
  7. Provide text descriptions for errors, not just red styling
  8. Integrate automated accessibility testing into CI
#无障碍#WCAG#对比度#色盲#色彩设计