色彩无障碍设计指南:对比度、色盲适配与 WCAG 合规实战

实用工具

色彩无障碍:不只是"好看"

全球约 8% 男性和 0.5% 女性存在色觉缺陷——每 12 个用户中就有 1 个无法正常辨别某些颜色。

色觉缺陷类型 患病率 难辨颜色
红色盲(Protanopia) 1% 红-绿
绿色盲(Deuteranopia) 5% 红-绿
蓝色盲(Tritanopia) 0.003% 蓝-黄
全色盲(Achromatopsia) 极罕见 全部

一、WCAG 对比度标准

三级标准

级别 正常文本 大文本 UI 组件
AA ≥ 4.5:1 ≥ 3:1 ≥ 3:1
AAA ≥ 7:1 ≥ 4.5:1 —

大文本定义:≥ 18pt(24px)或 ≥ 14pt 粗体(18.66px bold)。

对比度计算

对比度 = (L1 + 0.05) / (L2 + 0.05)

L1 = 较亮颜色的相对亮度
L2 = 较暗颜色的相对亮度

相对亮度 L:
  对于 sRGB 中 sRGB ≤ 0.03928: L = sRGB / 12.92
  对于 sRGB 中 sRGB > 0.03928: L = ((sRGB + 0.055) / 1.055)^2.4

  sRGB = R/255, G/255, B/255 (每个通道分别计算)

常见配色对比度

前景 背景 对比度 AA 正常文本 AA 大文本
#000000 #FFFFFF 21:1 ✅ ✅
#333333 #FFFFFF 12.6:1 ✅ ✅
#666666 #FFFFFF 5.7:1 ✅ ✅
#767676 #FFFFFF 4.5:1 ✅ (刚好) ✅
#999999 #FFFFFF 2.8:1 ❌ ❌
#FF0000 #FFFFFF 3.99:1 ❌ ✅
#0000FF #FFFFFF 8.59:1 ✅ ✅

二、使用工具库验证对比度

操作步骤

  1. 打开 颜色对比度工具
  2. 输入前景色和背景色(支持 HEX、RGB、HSL)
  3. 查看结果:
    • 对比度比值
    • WCAG AA / AAA 合规状态
    • 正常文本 / 大文本分别判定
  4. 调整颜色直到合规

三、色盲模拟

CSS filter 模拟

/* 红色盲 */
.protanopia { filter: url('#protanopia'); }

/* 绿色盲 */
.deuteranopia { filter: url('#deuteranopia'); }

/* 蓝色盲 */
.tritanopia { filter: url('#tritanopia'); }

SVG 滤镜矩阵

<svg style="display:none">
  <!-- 红色盲模拟矩阵 -->
  <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>

  <!-- 绿色盲模拟矩阵 -->
  <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>

四、色盲适配策略

策略一:不只依赖颜色传达信息

<!-- 错误:仅用颜色区分状态 -->
<span class="status-error" style="color: red">失败</span>
<span class="status-success" style="color: green">成功</span>

<!-- 正确:颜色 + 图标 -->
<span class="status-error" style="color: red">
  <svg>✕</svg> 失败
</span>
<span class="status-success" style="color: green">
  <svg>✓</svg> 成功
</span>

策略二:使用色盲友好配色

避免的组合 替代组合
红 + 绿 红 + 蓝,或 橙 + 蓝
浅红 + 浅绿 深红 + 浅绿
绿色成功 + 红色错误 蓝色信息 + 橙色警告

Wong 色盲友好配色板

#000000 黑色
#E69F00 橙色
#56B4E9 天蓝
#009E73 青绿
#F0E442 黄色
#0072B2 蓝色
#D55E00 朱红
#CC79A7 粉紫

这套配色在所有色觉缺陷类型下均可区分。

策略三:图表使用纹理/图案

/* 不同数据系列使用不同纹理 */
.series-a { background-image: url('stripes.svg'); }
.series-b { background-image: url('dots.svg'); }
.series-c { background-image: url('crosshatch.svg'); }

五、暗色模式无障碍

暗色模式对比度陷阱

陷阱 说明 解决
纯黑底纯白字 对比度 21:1,但易致眼疲劳 用深灰底 (#1a1a2e)
降低饱和度 暗色下高饱和度刺眼 适当降饱和度
阴影不可见 暗色背景上阴影消失 用边框或亮度差替代
图片对比度不足 暗色下图片细节丢失 CSS filter 调整

暗色模式配色建议

:root {
  /* 亮色模式 */
  --bg: #ffffff;
  --fg: #1a1a2e;
  --muted: #6b7280;
  --accent: #3b82f6;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1a2e;
    --fg: #e0e0e0;
    --muted: #9ca3af;
    --accent: #60a5fa; /* 更亮的蓝色,保持对比度 */
  }
}

六、组件级无障碍检查

表单错误提示

<!-- 错误:仅用红色边框提示 -->
<input style="border: 1px solid red" />

<!-- 正确:边框 + 文字 + aria -->
<input
  style="border: 1px solid red"
  aria-invalid="true"
  aria-describedby="error-msg"
/>
<span id="error-msg" role="alert" style="color: #dc2626">
  请输入有效的邮箱地址
</span>

链接与周围文本的对比

链接不仅需要与背景有足够对比度,还需要与周围文本有视觉区分:

/* 链接不仅靠颜色区分,还有下划线 */
a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

七、自动化检测

axe-core 集成

import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

test('色彩无障碍', async () => {
  const { container } = render(<MyComponent />);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

Lighthouse 审计

npx lighthouse https://example.com --only-categories=accessibility

CI 集成

- name: Accessibility check
  run: npx pa11y https://staging.example.com

八、最佳实践清单

  1. 文本对比度 ≥ 4.5:1(AA 级正常文本)
  2. 不只依赖颜色传达状态信息
  3. 使用色盲友好配色板(如 Wong 配色)
  4. 图表添加纹理/图案辅助区分
  5. 暗色模式保持对比度,避免纯黑底
  6. 链接有下划线或其他非颜色区分
  7. 错误提示有文字说明,不仅靠红色
  8. 自动化无障碍测试集成到 CI
#无障碍#WCAG#对比度#色盲#色彩设计