无障碍颜色对比度:WCAG 2.1 标准与前端实践

为什么前端必须关心颜色对比度

假设你做了一个登录页:品牌蓝按钮 + 白色文字,设计师觉得「很漂亮」,PM 觉得「很品牌」,但上线后收到反馈:「我在户外看不清按钮上的字」「我是色弱,文字和背景糊在一起」。

这就是颜色对比度问题。WCAG(Web Content Accessibility Guidelines,Web 内容无障碍指南)是 W3C 制定的国际标准,美国 ADA、欧盟 EN 301 549、中国信息无障碍国家标准都直接引用或参考 WCAG。许多国家的法律要求政府网站、商业网站达到 WCAG AA 级。

对比度过低会影响:

  • 色弱用户(约人口 8%,男性高达 12%):难以区分低对比色
  • 老年用户:晶状体老化导致对低对比度敏感度下降
  • 强光环境:户外、车内、办公室过亮时屏幕反光降低有效对比度
  • 低分辨率设备:小字号 + 低对比 = 双重难读

配套工具:颜色对比度检查工具

WCAG 2.1 对比度的数学定义

相对亮度(Relative Luminance)

WCAG 不直接用 RGB 值算对比度,而是先转换为相对亮度 L,模拟人眼对不同颜色的敏感度(绿色最敏感,蓝色最不敏感)。

每个 RGB 通道(0-255)先做 gamma 解码:

function channel(n) {
  const c = n / 255;
  // 0.03928 是 WCAG 2.1 修正后的阈值(原 0.04045)
  return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}

然后按人眼敏感度加权求和:

function relativeLuminance({ r, g, b }) {
  return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
}
  • 纯白(255, 255, 255)L = 1.0
  • 纯黑(0, 0, 0)L = 0.0
  • 纯绿(0, 255, 0)L ≈ 0.7152(最亮的原色)
  • 纯蓝(0, 0, 255)L ≈ 0.0722(最暗的原色)

对比度比值(Contrast Ratio)

两色的对比度公式:

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

其中 L1 为较亮色的相对亮度,L2 为较暗色的相对亮度。加 0.05 是为了补偿显示器的最低亮度(不是纯黑)和环境光反射,避免在低亮度区间得到过高的比值。

取值范围 1.0(同色)到 21.0(纯黑 vs 纯白)

function contrastRatio(rgb1, rgb2) {
  const L1 = relativeLuminance(rgb1);
  const L2 = relativeLuminance(rgb2);
  const lighter = Math.max(L1, L2);
  const darker = Math.min(L1, L2);
  return (lighter + 0.05) / (darker + 0.05);
}

WCAG 2.1 评级标准

WCAG 分为三个合规级别:A(最低)、AA(行业基准)、AAA(最高,特殊场景才要求)。

评级应用场景对比度阈值说明
AA普通文字(< 18px 或 < 14px 加粗)≥ 4.5:1正文、链接、按钮文字
AA大文字(≥ 18px 或 ≥ 14px 加粗)≥ 3.0:1标题、大号强调文字
AAA普通文字≥ 7.0:1增强对比度,医疗 / 政府关键信息
AAA大文字≥ 4.5:1增强对比度
AAUI 组件(按钮边框、图标、表单控件)≥ 3.0:1非文字元素边界

为什么大文字阈值低?因为大字号本身就更易读,「易读性 = 字号 × 对比度」,大字号可以抵消部分对比度不足。

为什么 AA 普通文字是 4.5:1 而不是 5:1?这是 W3C 基于色弱用户实测得出的阈值,4.5:1 时约 95% 的色弱用户能正常阅读。

常见配色场景对比度速查

以下是常见配色的对比度(用 对比度检查工具 验证):

前景色背景色对比度AA 普通文字AAA 普通文字
#000000#ffffff21.0:1
#1f2937 深灰#ffffff14.7:1
#374151 中灰#ffffff10.3:1
#6b7280 浅灰#ffffff4.8:1
#9ca3af 更浅灰#ffffff2.9:1
#2b6cff 品牌蓝#ffffff4.0:1
#1e3a8a 深蓝#ffffff8.6:1
#dc2626#ffffff4.3:1
#16a34a 绿#ffffff3.4:1
#ffffff#2b6cff 品牌蓝4.0:1

注意几个反直觉点:

  1. 品牌蓝 #2b6cff 文字在白底上不达 AA(4.0:1 < 4.5:1),但作为按钮背景 + 白色文字同样不达 AA。
  2. 浅灰 #9ca3af 作为正文色不达 AA,常见于「次要信息」灰色文字,但若作为正文则违规。
  3. 绿色 #16a34a 在白底上不达 AA,常见于「成功提示」,但作为正文文字不合规。

品牌色不达标的 4 种解决方案

品牌色(如公司 Logo 色)通常饱和度高、明度中等,与白色背景对比度往往不足 4.5:1。4 种解决思路:

方案 1:加深品牌色作为文字色

保留原品牌色用于按钮背景、图标等大面积色块,文字色使用更深的同色相变体

:root {
  --brand-primary: #2b6cff;     /* 原品牌色,按钮背景 */
  --brand-text: #1e3a8a;        /* 加深变体,文字色,对比度 8.6:1 */
}
.text-brand { color: var(--brand-text); }
.btn-primary { background: var(--brand-primary); color: #fff; }

颜色格式转换工具 把品牌色转 HSL,把 L(亮度)降低 20% 左右通常即可达标。

方案 2:加大字号使其符合「大文字」标准

大文字(≥ 18px 或 ≥ 14px 加粗)只需 ≥ 3.0:1。如果品牌色对比度 3.5:1,把字号从 14px 提到 18px即可合规。

.brand-heading {
  color: #2b6cff;       /* 4.0:1 不达普通 AA */
  font-size: 18px;      /* 但符合「大文字」标准,3.0:1 即达标 */
  font-weight: 400;
}

方案 3:更换背景色

把白底改为浅灰底,差异虽小但有时足够。#2b6cff#ffffff 上是 4.0:1,在 #f9fafb 上是 4.05:1(仍不达标),但在 #f3f4f6 上是 4.13:1(更接近但仍不达标)。这个方案效果有限,通常需要与方案 1 结合

方案 4:使用描边或下划线辅助

对于链接、按钮等可交互元素,如果对比度仅勉强达标,额外加下划线或描边提供视觉冗余。WCAG 1.4.1(颜色用途)要求「不能仅靠颜色传达信息」,下划线既符合这条又提升可读性。

a.brand-link {
  color: #2b6cff;
  text-decoration: underline;    /* 不依赖颜色识别 */
  text-underline-offset: 2px;
}

暗色模式下的对比度陷阱

许多人以为「暗色背景天然高对比」,这是错的。暗色模式同样需要满足 WCAG 对比度要求,常见陷阱:

配色对比度问题
#9ca3af 文字 + #1f2937 背景4.5:1勉强达 AA,但小字号下仍难读
#6b7280 文字 + #1f2937 背景2.7:1不达 AA,常见于「次要文字」
#374151 文字 + #1f2937 背景1.4:1严重不足,几乎不可读
#e5e7eb 文字 + #1f2937 背景11.6:1✓ 达 AAA

建议暗色模式下:

  • 文字色至少使用 #e5e7eb 以上亮度(L > 0.7)
  • 次要文字色至少 #d1d5db(L > 0.6)
  • 背景色不超过 #1f2937(L ≈ 0.03)
  • 避免在中灰背景 #374151 上放任何文字

渐变与图片背景的处理

WCAG 对渐变与图片背景没有精确公式,建议做法:

  1. 渐变背景:在渐变最浅和最两端分别测文字对比度,取较低值作为合规判定。如果一端不达标则整体不达标。
  2. 图片背景:在图片上叠加半透明遮罩(如 rgba(0,0,0,0.5))后再测文字对比度。遮罩颜色应与文字色形成高对比(深色遮罩 + 浅色文字)。
  3. 复杂图片背景:若无法保证一致对比度,应改为纯色卡片背景文字区,把文字放在不透明卡片上。
.hero-overlay {
  position: relative;
}
.hero-overlay::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);  /* 遮罩提升对比度 */
}
.hero-overlay h1 {
  position: relative;
  color: #ffffff;                  /* 白字 + 半透明黑遮罩 = 高对比 */
}

工具矩阵:颜色相关工具联动

本站颜色相关工具:

典型工作流:

  1. 颜色格式转换选品牌色(拾色器 + 配色方案)
  2. 把候选前景色与背景色复制到颜色对比度检查验证是否达标
  3. 不达标时用方案 1(加深文字色)调整,回到第 1 步转换为新 HEX
  4. 最终在 对比度检查工具 确认所有 5 项评级通过 AA

小结

WCAG 颜色对比度不是「设计师的洁癖」,而是真实用户能否阅读你的界面的硬指标。记住几个关键数字:

  • 4.5:1:普通文字 AA(行业基准)
  • 3.0:1:大文字 AA + UI 组件 AA
  • 7.0:1:普通文字 AAA(增强)

品牌色不达标时优先加深文字色变体,原色保留给大面积色块。暗色模式下不要假设天然高对比,同样需要逐一验证。本站的 对比度检查工具 完全使用 WCAG 官方公式,结果与 W3C 计算器一致,可在开发流程中随时调用。