无障碍设计

蓝色按钮的文字如何选?用 WCAG 实例验证对比度

计算常见蓝色按钮的文字对比度,理解白字为什么可能不达标,并比较调整前景色与背景色后的 WCAG AA 检查结果。

先确认文字需要达到什么标准

WCAG 2.2 成功准则 1.4.3 要求,AA 级普通文字对比度至少为 4.5:1,大文字至少为 3:1。大文字指不小于 18 pt,或者不小于 14 pt 的粗体,约对应 24 CSS px 或 18.67 CSS px。常见的 16 px 按钮文字即使加粗,也需要达到 4.5:1。

应比较标签文字与其直接背景。蓝色看起来鲜艳,并不代表足够深、适合使用白字。设计系统中的 Token 名称,或者某一块屏幕上的主观观感,都不能替代准确计算。

比较真实蓝色上的白字与深色文字

下表使用不透明 sRGB 颜色与 WCAG 相对亮度公式计算。显示值保留两位小数,是否通过则按未舍入的结果判断,不能通过向上取整来跨过标准门槛。

#3B82F6 上的白字无法满足普通文字 AA,而 #111827 可以。将背景加深到 #2563EB 后,白字也可以通过。Ant Design 默认色 #1677FF 则说明前景色需要实际测试:这里比较的白色和 #111827 都没有达到 4.5:1。

不透明蓝色背景上的普通文字 WCAG AA 检查
背景色文字色对比度普通文字 AA
#3B82F6#FFFFFF3.68:1未通过
#3B82F6#1118274.82:1通过
#2563EB#FFFFFF5.17:1通过
#1677FF#FFFFFF4.10:1未通过
#1677FF#1118274.32:1未通过
#3F51B5#FFFFFF6.87:1通过

正确解释对比度结果与适用范围

对比度属于两个颜色的组合,不能单独归属于某个蓝色。#1677FF 的两项未通过示例,不代表所有深色前景都无法通过,也不代表组件库在全部配置下都不满足要求。更换前景、使用其他派生状态或定制主题后,都需要重新测量。评价组件前,应先记录实际使用的 CSS 色值。

通过结果也与具体标准有关。AAA 级普通文字需要 7:1,大文字需要 4.5:1。因此 5.17:1 可以通过普通文字 AA,却不能通过普通文字 AAA。向团队交付结果时,应同时注明级别、文字尺寸与颜色组合,避免只把某个颜色笼统地标记为无障碍颜色。

设计允许时,可以为最低门槛留出一定余量。W3C 提醒,细字重或特殊字体在抗锯齿处理后,可能看起来比 CSS 指定颜色更浅。正式计算使用指定的前景与背景,再通过真实渲染检查可读性;不能从文字柔化边缘随意取一个像素,作为文字对比度的计算依据。

正确计算相对亮度

将每个 0–255 的 sRGB 通道除以 255。如果归一化结果不大于 0.04045,再除以 12.92;否则计算 ((通道值 + 0.055) / 1.055) 的 2.4 次方。使用线性化后的通道计算相对亮度:0.2126R + 0.7152G + 0.0722B。

对比度等于(较亮颜色的亮度 + 0.05)除以(较暗颜色的亮度 + 0.05)。下面的代码只接受不透明六位 HEX。遇到透明层或渐变时,应先确定文字所在位置实际显示的颜色,再代入公式。

JavaScript
function luminance(hex) {
  if (!/^#[0-9a-f]{6}$/i.test(hex)) {
    throw new Error('Expected an opaque #RRGGBB color');
  }
  const channels = [1, 3, 5].map((start) => {
    const value = parseInt(hex.slice(start, start + 2), 16) / 255;
    return value <= 0.04045
      ? value / 12.92
      : ((value + 0.055) / 1.055) ** 2.4;
  });
  return channels[0] * 0.2126
    + channels[1] * 0.7152
    + channels[2] * 0.0722;
}

function contrastRatio(foreground, background) {
  const values = [luminance(foreground), luminance(background)];
  return (Math.max(...values) + 0.05) / (Math.min(...values) + 0.05);
}

const ratio = contrastRatio('#FFFFFF', '#2563EB');
console.log(ratio.toFixed(2)); // 5.17
console.log(ratio >= 4.5);     // true

通过组件语义修正不达标的按钮

以 #3B82F6 背景上的 16 px 白色标签为例,先确认它属于普通文字,且背景完全不透明。其对比度约为 3.68:1,仅增加字重仍不能通过。如果主按钮需要保留白字,可以将操作背景调整为 #2563EB,普通状态下的对比度约为 5.17:1。

如果原背景必须保留,那么在这个蓝色上使用 #111827 文字可得到约 4.82:1。结合组件层级与品牌要求选择方案后,应修改按钮使用的语义 Token。直接替换全站品牌色,可能同时影响插画、链接、选中背景和其他对比度关系不同的组件,扩大修改范围。

无论选择哪种方案,都要分别检查悬停与按下样式。普通状态达标的按钮,可能因为悬停时背景变浅,或者整个元素被设置 opacity 而再次失效。整体透明度会同时影响文字和填充,应检查最终合成组合。遇到渐变或图片,则需要检查文字覆盖区域中对比度最低的位置,不能只测背景平均色。

检查所有交互状态

选择通过要求的前景与背景后,还要检查悬停、按下、选中和聚焦状态。渐变背景需要覆盖文字所在区域中对比度最低的位置;半透明背景则必须先与实际底色合成。

文字对比度只是无障碍的一部分。WCAG 1.4.11 对部分非文字界面元素和图形提出 3:1 的对比度要求,键盘焦点也必须可见。标签文字达到 4.5:1,并不代表组件或页面已经满足全部 WCAG 要求。

应识别哪些视觉信息是辨认控件或状态所必需的,再与相邻颜色比较。这不代表所有装饰边框都需要达到 3:1,也不要求没有相邻显示的悬停填充与普通填充互相比出 3:1。自定义焦点指示需要检查接触到的颜色,并通过键盘操作确认提示确实可见。

相关对比度准则对非活动控件设有例外,但应确认控件确实不可用。不能给仍可操作的按钮套用类似禁用的样式,就免除其文字要求。次要操作、辅助说明和占位文字,也不会因为视觉优先级较低而自动获得豁免。

可以用分析器检查背景色对应的文字建议。如果设计指定了前景色,应计算这一准确组合,不要默认工具推荐的深色或浅色文字与最终 CSS 完全一致。

留下可以重复验证的检查记录

为每个按钮变体记录主题、状态、前景、最终背景、字号、字重、未舍入对比度和适用门槛。涉及透明度时,还要记录下层表面。展示时可以保留两位小数,但计算结果应保留足够精度,不能把 4.499:1 当成达到 4.5:1。

自动检查适合发现简单颜色组合的问题,但渐变、图片、叠加层和动态状态通常还需要人工补充。应在浏览器中检查计算样式,通过键盘操作控件,并验证实际悬停与按下状态。截图说明上下文,保存的颜色与计算过程则让另一位评审者能够复现结论。

主题种子、组件覆盖、字体或背景变化后,都应重复检查。将结果视为某个具体组件配置的证据,并准确描述覆盖范围:文字对比度是已经验证的一项要求,完整无障碍评估还包括名称、键盘操作、焦点以及其他适用准则。

来源与延伸阅读

← 返回全部文章