色彩无障碍设计指南:对比度、色盲适配与 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 | ✅ | ✅ |
二、使用工具库验证对比度
操作步骤
- 打开 颜色对比度工具
- 输入前景色和背景色(支持 HEX、RGB、HSL)
- 查看结果:
- 对比度比值
- WCAG AA / AAA 合规状态
- 正常文本 / 大文本分别判定
- 调整颜色直到合规
三、色盲模拟
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
八、最佳实践清单
- 文本对比度 ≥ 4.5:1(AA 级正常文本)
- 不只依赖颜色传达状态信息
- 使用色盲友好配色板(如 Wong 配色)
- 图表添加纹理/图案辅助区分
- 暗色模式保持对比度,避免纯黑底
- 链接有下划线或其他非颜色区分
- 错误提示有文字说明,不仅靠红色
- 自动化无障碍测试集成到 CI
#无障碍#WCAG#对比度#色盲#色彩设计