关于 color-contrast
color-contrast 是面向视觉界面实现与审查的颜色对比度可访问性技能,适用于 HTML、CSS、SVG 等界面。它覆盖文本、控件状态、主题和强制颜色模式,并要求信息不能只靠颜色传达。
主要功能
- 01文本对比度要求
- 02非文本组件对比度
- 03避免仅用颜色传递信息
- 04强制颜色模式适配
- 05主题与状态验证
适用场景
- 01检查浅色与深色主题的文本对比
- 02验证图标、控件及焦点状态
- 03审查图表与状态是否依赖颜色
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mgifford/ accessibility-skills --skill color-contrast安装后在 Claude Code 中输入/color-contrast确认已加载。
附带文件SYNC.md
详细介绍
色彩对比度无障碍技能
规范来源:
examples/COLOR_CONTRAST_ACCESSIBILITY_BEST_PRACTICES.md(位于mgifford/ACCESSIBILITY.md中) 此技能根据该文件编写。如有疑问,请以该示例为准。
在实现或审查 HTML、CSS、SVG 中的颜色选择,或任何视觉界面元素时,都应遵循这些规则。
核心要求
前景与背景之间有足够的对比度,是用户阅读文本、识别 UI 组件、感知图形内容以及跟踪键盘焦点的前提。绝不能仅靠颜色来传达信息。 对比度取决于应用不透明度、渐变、图像、覆盖层、状态和主题后实际相邻的颜色——调色板符合要求,并不代表最终界面也符合要求。
所有传达信息或需要用户交互的视觉界面元素,都必须在浅色模式、深色模式和强制颜色(高对比度)模式下满足 WCAG 2.2 AA 级对比度阈值。
严重程度分级(本技能)
| 级别 | 含义 |
|---|---|
| 严重 | 对比度不达标,导致内容或交互完全无法访问 |
| 高 | 对比度不达标,显著影响某个残障群体访问内容 |
| 中 | 对比度问题降低了可用性,但内容仍可部分访问 |
| 低 | 未遵循最佳实践;影响较小 |
时间有限时,请按对用户的影响优先处理:(1)完成任务所需的文本/控件,(2)键盘焦点指示器和组件状态,(3)错误/警告/必填字段/状态消息,(4)导航/链接/标签,(5)图表和承载信息的图形,(6)辅助/次要内容。
严重:文本对比度(WCAG 1.4.3)
| 文本类型 | 最低值(AA) | 增强值(AAA) |
|---|---|---|
| 普通文本(小于 18pt / 14pt 粗体) | 4.5:1 | 7:1 |
| 大号文本(18pt 及以上,或 14pt 及以上粗体) | 3:1 | 4.5:1 |
| 标志 / 纯装饰性文本 | 豁免 | 豁免 |
| 禁用控件 | 豁免 | 豁免 |
**“大号文本”**指常规字重下 18pt(≈ 24 CSS px)或更大,或粗体下 14pt(≈ 18.67 CSS px)或更大。WCAG 阈值是通过/不通过的判定标准——不要把 4.499:1 四舍五入到 4.5:1。对细笔画或不常见的字体应谨慎处理——即使计算结果达到阈值,笔画较细仍可能导致难以阅读。
此要求适用于正文、标题、链接文本、按钮/表单标签、占位符文本、悬停/聚焦时显示的文本、验证/状态消息,以及以图像形式呈现的文本。不要将标志/装饰性文本的豁免扩大到用于普通内容的品牌色。
如果 CSS 仅指定前景色或仅指定背景色,另一侧可能取决于未知的用户偏好——请始终同时指定一组颜色的两侧:
html { background: #ffffff; color: #1b1f23; }
.notice { background: #f2f6fa; color: #243447; }
/* Bad — fails 1.4.3 */
.placeholder { color: #aaaaaa; }
.note { color: #888; }
优先使用真实文本,而非文本图像(WCAG 1.4.5)——真实文本可重排、缩放并适应主题;仅在呈现方式可自定义或不可或缺时,才使用文本图像。
严重:非文本对比度(WCAG 1.4.11)
用于识别 UI 组件或其状态的视觉信息,以及理解图形所需的部分,都需要与相邻颜色达到 3:1 的对比度。例如:用于识别控件的复选框边界、表示选中状态的勾号、仅图标按钮中的图标、滑块滑块/轨道、错误边界,以及阅读图表所需的线条/扇区/符号。
这并不意味着每条装饰性边框都必须达到 3:1——如果文本、形状、位置或其他处理方式已能识别组件/状态,那么低对比度的装饰性边框未必是必需信息。不适用于:纯装饰性图形、非活动/已禁用组件、徽标/品牌标志,或作为相邻文本补充的图形。
原生控件是可靠的默认选择——浏览器/操作系统会根据用户偏好进行调整;替换它们意味着你需要负责处理每种状态和模式:
.checkbox {
appearance: none;
inline-size: 1.25rem;
block-size: 1.25rem;
border: 2px solid #59636e; /* test against surrounding background */
border-radius: 0.2rem;
}
.checkbox:checked {
border-color: #005ea8;
background-color: #005ea8;
}
请测试未选中边界与背景之间、选中填充与周围背景之间,以及勾号与选中填充之间的对比度——不要依赖声称某组颜色对比合格的代码注释;应测量实际渲染的组合。图标描边使用 currentColor,使其能随按钮的文本颜色调整。
严重:颜色的使用(WCAG 1.4.1)
颜色不能成为传达信息、提示响应或区分元素的唯一手段。只要颜色承载含义,就应添加可见文本、形状、图案、图标或其他非颜色提示。
<label style="color: red;">Email address</label>
<input type="email" style="border-color: red;">
<div class="field" data-state="error">
<label for="email">Email address <span aria-hidden="true">(required)</span></label>
<input id="email" type="email" required aria-invalid="true" aria-describedby="email-error">
<p id="email-error" class="error-message">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M12 3 2 21h20L12 3Zm0 6v5m0 3v.01"></path>
</svg>
Enter an email address in the format [email protected].
</p>
</div>
正文中的链接必须通过颜色以外的方式与周围文本区分——添加下划线是最简单可靠的做法:
a {
color: #005ea8;
text-decoration-line: underline;
text-decoration-thickness: max(1px, 0.08em);
}
一项已记录的例外(WCAG 技术 G183)允许链接默认不带下划线,前提是链接文本与周围文本的对比度至少为 3:1,并且在悬停/聚焦时会出现非颜色提示——这种做法更难维护;对于正文,建议始终显示下划线。图表/状态指示器除了颜色之外,还需要标签、符号、线型或图案——单独提供文本等效表格,并不能免除图形本身满足对比度要求的义务。
严重:键盘焦点外观
WCAG 2.2 AA 要求提供可见的焦点指示器(2.4.7)。2.4.13 焦点外观属于 AAA 级别——不要将其面积/对比度变化公式说成 AA 要求。WCAG 1.4.11 仍可能适用于作者创建的焦点指示器,因为它是用于识别聚焦状态的视觉信息。
/* Start with the browser default; don't remove without a tested replacement */
:focus-visible {
outline: 3px solid #005fcc;
outline-offset: 3px;
}
/* Two-color indicator — more robust across light/dark surfaces */
:focus-visible {
outline: 3px solid #ffffff;
outline-offset: 2px;
box-shadow: 0 0 0 5px #111111;
}
@media (forced-colors: active) {
:focus-visible {
outline: 3px solid Highlight;
box-shadow: none;
}
}
/* NEVER do this without a tested replacement */
:focus { outline: none; }
不要将 :focus:not(:focus-visible) { outline: none; } 作为通用规则添加——浏览器已经会判断何时匹配 :focus-visible,而一概抑制焦点样式存在风险。请在每种表面和组件状态下测试指示器的几何形状、裁切情况和相邻颜色。
严重:强制颜色模式
Windows 高对比度模式 / forced-colors 会将作者设置的颜色替换为系统颜色。当 background-color、box-shadow 或 color 成为传达含义的唯一手段时,界面就会出现问题——outline 在强制颜色模式下仍会保留;box-shadow 则可能被抑制。
@media (forced-colors: active) {
.status-icon, .icon-button svg { fill: none; stroke: currentColor; }
[aria-current="page"] { border-block-end: 0.25rem solid currentColor; }
[aria-invalid="true"] { border: 3px solid Mark; }
}
优先使用原生控件和语义化 HTML;只有在测试发现信息消失时,才添加针对性修正。除非保留作者设置的颜色至关重要,且已针对多种用户选择的系统调色板进行测试,否则应避免使用 forced-color-adjust: none——它会使元素退出该模式的保护机制。
**测试:**在“辅助功能”设置中启用 Windows 高对比度;Chrome DevTools → Rendering → “Emulate CSS media feature forced-colors: active”;Firefox about:config → ui.forcedColors: 1。
中等:主题和语义颜色令牌
验证完整的前景色与背景色组合,而不是孤立的颜色。语义令牌能明确预期的配对关系:
:root {
color-scheme: light dark;
--surface: light-dark(#ffffff, #15191e);
--text: light-dark(#1b1f23, #f4f6f8);
--link: light-dark(#005ea8, #73b7f2);
--control-border: light-dark(#59636e, #a7b0ba);
}
html { background: var(--surface); color: var(--text); }
.card { background: var(--surface); color: var(--text); border: 1px solid var(--control-border); }
如果项目的浏览器支持策略允许,light-dark() 会很有用;对于较旧的浏览器,请提供自定义属性回退方案。手动实现主题选择器的方法请参阅 skills/light-dark-mode/SKILL.md。
不要假设 CSS 颜色函数能保证可访问性——color-mix() 会生成介于两个输入值之间的颜色,但不会以 WCAG 对比度比率为目标;在当前实现中,contrast-color() 只会从有限的结果集中选取颜色,不能取代对文本/组件/状态要求的验证。请将二者视为实现辅助工具,而非符合性测试。
/* Bad: hard-coded value that may fail in dark mode */
.card { background-color: #ffffff; color: #333; }
严重:可变背景、不透明度和叠加层
对于渐变、图像、视频或半透明表面上的文本,请测试正常使用中可能出现的渲染效果最不理想的区域。如果无法控制底层内容,请使用不透明或具有足够不透明度的底色表面:
.hero-title {
display: inline;
padding: 0.15em 0.35em;
color: #ffffff;
background: #16202a;
box-decoration-break: clone;
}
谨慎对父元素使用 opacity——它会将文本和背景与组件后方的内容混合,从而改变对比度组合的两侧:
/* Avoid: reduces opacity of the whole component */
.secondary-card { opacity: 0.6; }
/* Prefer: explicit, validated colors */
.secondary-card { background: #f2f6fa; color: #4d5966; }
自动化工具可能会将可变背景报告为“不完整”——这是测试的局限性,并不能证明内容符合要求。
中等:需要单独验证的状态
检查用户可能遇到的组件各个状态:默认、悬停、键盘焦点、激活/按下、已选中/已勾选、已访问、无效/错误、成功/警告/信息、已禁用/非活动、浏览器自动填充、文本选区,以及打开/展开/当前状态。在每种受支持的主题下重复检查。
禁用控件可免于遵守 1.4.3/1.4.11 的特定比率要求,但这项豁免并非设计目标:条件允许时,应确保禁用控件仍可被识别;不要只通过颜色传达禁用状态;必要时说明控件不可用的原因;并考虑是否确实需要禁用它(与其使用一个原因不明的不可用按钮,不如允许用户尝试提交并提供清晰的验证提示,这可能更容易理解)。
<button type="submit" disabled aria-describedby="submit-help">Submit</button>
<p id="submit-help">Add at least one contact before submitting.</p>
中等:用户对比度偏好
prefers-contrast 和 forced-colors 针对不同情况——二者都不是浅色/深色主题选择器。将 prefers-contrast: more 用作增强功能;默认呈现必须已经达到符合性目标:
@media (prefers-contrast: more) {
:root { --text-muted: var(--text); --control-border: currentColor; }
a { text-decoration-thickness: 0.15em; }
:focus-visible { outline-width: 4px; }
}
轻微:APCA——新兴标准(尚未强制要求)
高级感知对比度算法(APCA)是 WCAG 3.0 中拟用于取代 WCAG 2.x 对比度公式的候选方案,它能更准确地模拟细线条和小号文本的视觉感知。目前尚未强制要求使用 APCA——尝试使用该算法的团队仍必须同时满足 WCAG 2.2 AA。不要将固定的 APCA 阈值说成当前的 WCAG 要求;只能将实验性方法视为补充性的设计依据。
测试
手动测试: 检查实际渲染的前景色和背景色(而非源代码中的值);测量文本颜色对,且不进行取整;确定查找每个组件/状态所需的视觉信息,并对照相关的相邻颜色进行测量;使用 Tab 键逐项浏览,并检查各个背景上的焦点状态;测试所有主题和组件状态;测试 Windows 高对比度/强制颜色模拟;手动检查渐变、图像、不透明度、叠加层、粘性内容和文本选中效果。灰度/色觉模拟可用于辅助审查,但不能替代基于标准的测试或亲身体验。
自动化测试:
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
for (const theme of ["light", "dark"]) {
test(`automated accessibility scan: ${theme}`, async ({ page }) => {
await page.goto("/");
await page.locator("html").evaluate((el, value) => { el.dataset.theme = value; }, theme);
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});
}
自动化工具可以发现许多可计算的文本对比度问题,但无法可靠地判断所有背景、必需的图形细节、仅通过颜色区分的信息、焦点指示器的几何形状或强制颜色模式下的问题——应使用自动化辅助人工审查,而不是取而代之。focus-visible 和 focus-order-semantics 并非真实的 axe-core 规则 ID——不要引用它们;键盘焦点外观需要手动测试(实际规则集请参见 skills/axe-rules/SKILL.md)。
设计令牌: 维护一份明确的、已批准的令牌配对列表,并在令牌变更时测试这些配对——不要将每个令牌与其他所有令牌逐一测试,因为许多组合并非有效用法。仍需进行运行时测试,因为组件 CSS 可能引入令牌测试未覆盖的不透明度/叠加层。
完成定义检查清单
- 所有普通文本在浅色和深色模式下均满足 4.5:1 的对比度(或记录例外情况)
- 所有大号文本在浅色和深色模式下均满足 3:1 的对比度
- 表单控件、图标和数据可视化元素均满足 3:1 的非文本对比度
- 不存在仅通过颜色传达的信息——图标、文本和颜色结合使用
- 正文中的链接无需颜色也能与周围文本区分开
- 焦点指示器使用
outline,对比度达到 3:1,并且在所有模式/表面上均可见 - 颜色令牌定义为 CSS 自定义属性;组件中没有硬编码值
- 已测试每种受支持的主题和组件状态(悬停、焦点、激活、选中、已访问、错误、禁用、自动填充、文本选中)
- 已在最不利区域测试渐变/图像/叠加层上的文本
- 已测试强制颜色模式/Windows 高对比度模式——没有丢失任何含义
- axe-core
color-contrast规则在 CI 中通过(仍需人工审查) - 除不透明度/颜色外,禁用控件还能与启用控件清晰区分
- 已记录并测试已批准的设计令牌配对
关键 WCAG 标准
- 1.4.1 颜色的使用(A)——不符合时为严重问题
- 1.4.3 最低对比度(AA)——普通文本不符合时为关键问题
- 1.4.5 文本图像(AA)
- 1.4.6 增强对比度(AAA)
- 1.4.11 非文本对比度(AA)——不符合时为严重问题
- 2.4.7 焦点可见(AA)
- 2.4.13 焦点外观(AAA,WCAG 2.2)——非 AA 要求
参考资料
- 完整的最佳实践指南
- WCAG 2.2 理解 1.4.1 色彩的使用
- WCAG 2.2 理解 1.4.3 对比度(最低)
- WCAG 2.2 理解 1.4.11 非文本对比度
- WCAG 2.2 理解 2.4.13 焦点外观
- 技术 G183:通过颜色和其他线索标识链接
- 技术 C40:双色焦点指示器
- 媒体查询第 5 级:
prefers-contrast - APCA 对比度工具
标准展望: WCAG 3.0 提议的 APCA 将以感知对比度模型取代现行的亮度比模型。在 WCAG 3.0 成为已发布标准之前,请勿在生产环境的符合性工作中应用 APCA。 关注:https://www.w3.org/TR/wcag-3.0/ 和 https://git.apcacontrast.com/