关于 accessibility
面向开发者的网页无障碍审查技能,可按 WCAG 要求检查界面。内容涵盖语义化 HTML、ARIA、键盘操作、对比度、屏幕阅读器及 WCAG 2.2,并指导生成审查报告。
主要功能
- 01WCAG 合规性审查
- 02语义化 HTML 与 ARIA 指引
- 03键盘导航检查
- 04颜色对比度验证
- 05屏幕阅读器与表单检查
- 06生成审查报告
适用场景
- 01审查 React 组件
- 02检查 CSS 颜色对比度
- 03检查表单无障碍性
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ oimiragieo/ agent-studio --skill accessibility安装后在 Claude Code 中输入/accessibility确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
commands/accessibility.mdhooks/post-execute.cjspre-execute.cjsreferences/accessibility.mdcresearch-requirements.mdrules/accessibility.mdschemas/input.schema.jsonoutput.schema.jsonscripts/main.cjstemplates/implementation-template.md详细介绍
无障碍技能
你是一名无障碍专家,专注于符合 WCAG 2.2 标准(包括全部 9 项新增成功准则)、语义化 HTML、ARIA 属性、键盘导航和辅助技术支持。WCAG 2.2 是当前的 W3C 推荐标准(2023 年 10 月),也是 ISO/IEC 40500:2025 国际标准。 - 审查代码是否符合无障碍标准(WCAG 2.1 AA/AAA) - 建议改进语义化 HTML - 实现适当的 ARIA 属性 - 确保支持键盘导航 - 验证颜色对比度 - 测试屏幕阅读器兼容性 - 生成无障碍审计报告 ## 无障碍分步审查流程步骤 1:语义化 HTML 审计
检查组件结构是否使用了恰当的语义元素:
检查以下内容:
- 使用
<header>、<nav>、<main>、<article>、<section>、<aside>、<footer>,而不是通用的<div> - 对可点击元素使用
<button>(不要使用<div onclick>) - 对导航链接使用
<a> - 表单使用
<form>、<input>、<label> - 标题层级恰当(
<h1>至<h6>)
示例:
<div class="header">
<div claass="nav">
<div class="nav-item" onclick="navigate()">Home</div>
</div>
</div>
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
步骤 2:ARIA 属性审查
仅当语义化 HTML 不足以满足需求时,才添加 ARIA 属性:
常见模式:
| 用例 | ARIA 属性 | 示例 |
|---|---|---|
| 自定义按钮 | role="button"、tabindex="0" | <div role="button" tabindex="0"> |
| 模态对话框 | role="dialog"、aria-modal="true" | <div role="dialog" aria-modal="true"> |
| 警报 | role="alert"、aria-live="assertive" | <div role="alert">Error occurred</div> |
| 标签面板 | role="tabpanel"、aria-labelledby | <div role="tabpanel" aria-labelledby="tab-1"> |
规则:
- 不要添加冗余的 ARIA(
<button role="button">没有必要) - 对没有文本的图标按钮使用
aria-label - 对装饰性元素使用
aria-hidden="true" - 对动态内容使用
aria-live区域
示例:
<button aria-label="Close dialog">
<i class="icon-close" aria-hidden="true"></i>
</button>
<div role="alert" aria-live="assertive">Form submitted successfully</div>
步骤 3:键盘导航测试
确认所有交互元素都可通过键盘访问:
要求:
- Tab:向前浏览交互元素
- Shift+Tab:向后浏览
- Enter/Space:激活按钮和链接
- 方向键:在组件内导航(标签、菜单、列表框)
- Escape:关闭对话框和菜单
焦点管理:
- 将焦点限制在模态框内(防止 Tab 导航到外部)
- 关闭模态框时,将焦点返回到触发元素
- 为屏幕阅读器用户提供跳转到主要内容的链接
- 提供可见的焦点指示器(
:focus样式)
示例:
// Focus trap in modal
function openModal(modal) {
modal.style.display = 'block';
const firstFocusable = modal.querySelector('button, input, a');
firstFocusable.focus();
trapFocus(modal); // Prevent escape from modal
}
function trapFocus(container) {
const focusableElements = container.querySelectorAll('button, input, select, textarea, a[href]');
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
container.addEventListener('keydown', e => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstElement) {
lastElement.focus();
e.preventDefault();
} else if (!e.shiftKey && document.activeElement === lastElement) {
firstElement.focus();
e.preventDefault();
}
}
});
}
步骤 3B:WCAG 2.2 新增成功准则(2023 年 10 月,ISO/IEC 40500:2025)
WCAG 2.2 新增了 9 项成功准则。请确认符合适用的准则:
2.4.11 焦点未被遮挡——最低要求(AA)
当键盘焦点所在元素滚动进入视野时,不得被粘性页眉/页脚或重叠的界面元素完全遮挡。焦点元素必须始终至少有一部分可见。
/* Prevent focus from hiding behind sticky headers */
:focus-visible {
scroll-margin-top: 80px; /* Height of sticky header + buffer */
scroll-margin-bottom: 60px; /* Height of sticky footer + buffer */
}
**测试:**使用 Tab 浏览所有交互元素,确认没有元素完全被横幅、Cookie 通知或粘性栏遮挡。
2.4.12 焦点未被遮挡——增强要求(AAA)
焦点所在组件必须完全可见(而不仅仅是部分可见)。粘性界面元素不得与焦点重叠。
2.4.13 焦点外观(AAA)
焦点指示器必须满足以下要求:面积至少为未聚焦组件周长乘以 2 个 CSS 像素;聚焦状态与未聚焦状态之间的对比度至少为 3:1。
/* Meeting 2.4.13 Focus Appearance (AAA) */
:focus-visible {
outline: 3px solid #005fcc;
outline-offset: 2px;
/* 3px thickness > 2px minimum; #005fcc on white = 7.1:1 contrast */
}
2.5.7 拖动操作(AA)
所有拖放功能都必须提供单指针(点击/轻触)替代方式。无法执行精确拖动手势的用户必须能够完成相同任务。
<ul>
<li draggable="true" id="item-1">
Item 1
<button aria-label="Move Item 1 up" onclick="moveUp('item-1')">↑</button>
<button aria-label="Move Item 1 down" onclick="moveDown('item-1')">↓</button>
</li>
</ul>
<input type="range" min="0" max="100" value="50" aria-label="Volume" />
<input type="number" min="0" max="100" value="50" aria-label="Volume value" />
测试: 找出所有拖动交互。确认每项交互都有非拖动的替代方式(按钮、上下文菜单、键盘快捷键)。
2.5.8 目标尺寸——最低要求(AA)
所有指针目标(按钮、链接、复选框、单选输入框)必须至少为 24x24 CSS 像素,或者间距足够,使 24x24 的区域不会与其他目标重叠。
/* Ensure minimum target size */
button,
a,
input[type='checkbox'],
input[type='radio'],
select {
min-width: 24px;
min-height: 24px;
}
/* Inline links: use padding to increase hit area without visual size change */
a {
padding: 4px 0;
}
/* Recommended: 44x44 CSS pixels for primary actions (mobile-friendly) */
.primary-action {
min-width: 44px;
min-height: 44px;
}
测试: 测量所有交互元素。确认没有元素小于 24x24 CSS 像素(使用浏览器 DevTools 元素检查器)。
3.2.6 帮助信息一致性(A)
如果帮助机制(联系链接、聊天小组件、电话号码、常见问题链接)出现在多个页面上,那么它在页面内容中的相对顺序必须一致。
<footer>
<nav aria-label="Help resources">
<a href="/faq">FAQ</a>
<a href="/contact">Contact Support</a>
<a href="tel:+18005551234">1-800-555-1234</a>
</nav>
</footer>
测试: 在不同页面间导航。确认每次出现的帮助链接/小组件顺序相同。
3.3.7 重复输入(A)
再次请求用户曾在同一会话/流程中输入的信息时,必须自动填充该信息或提供该信息供用户选择(例如,多步骤结账表单)。
<fieldset>
<legend>Billing Address</legend>
<label>
<input type="checkbox" id="same-as-shipping" />
Same as shipping address
</label>
</fieldset>
例外: 为安全确认而重新输入密码、从列表中选择项目。
3.3.8 无障碍身份验证——最低要求(AA)
身份验证流程不得要求用户完成认知功能测试(解谜、识别图像、记忆/抄录代码),除非提供无障碍替代方式。
允许的替代方式:
- 生物识别身份验证(指纹、人脸识别)
- 电子邮件魔法链接 / SMS OTP(用户无需记住代码,只需复制粘贴)
- 通过第三方提供商使用 OAuth
- 允许使用密码管理器(不要阻止在密码字段中粘贴)
<input type="password" id="password" autocomplete="current-password" />
<div role="group" aria-labelledby="captcha-label">
<span id="captcha-label">Verify you are human</span>
<img src="captcha.png" alt="CAPTCHA challenge" />
<input type="text" aria-describedby="captcha-label" />
<a href="?audio-captcha">Use audio CAPTCHA instead</a>
<a href="?email-login">Use email link instead</a>
</div>
测试: 找出所有身份验证步骤。确认没有任何步骤在未提供替代方式的情况下要求认知测试。
3.3.9 无障碍身份验证——无例外(AAA)
即使提供了替代方式,也不得要求进行认知功能测试。
步骤 4:验证颜色对比度
检查所有文本是否符合 WCAG 对比度要求:
标准:
| 文本大小 | WCAG AA | WCAG AAA |
|---|---|---|
| 正常文本(< 18pt) | 4.5:1 | 7:1 |
| 大文本(≥ 18pt 或 14pt 粗体) | 3:1 | 4.5:1 |
| UI 组件 | 3:1 | - |
工具:
- WebAIM 对比度检查器
- 浏览器 DevTools 颜色选择器
- 灰度测试(转换为灰度以验证可读性)
示例:
/* ❌ BAD - Innsufficient contrast */
.text {
color: #777;
background: #fff;
} /* 4.47:1 - fails AA */
/* ✅ GOOD - Sufficient contrast */
.text {
color: #595959;
background: #fff;
} /* 7:1 - passes AAA */
/* ✅ GOOD - Don't rely on color alone */
.error {
color: #d00;
border-left: 4px solid #d00; /* Visual indicator beyond color */
}
.error::before {
content: '⚠️ ';
} /* Icon indicator */
步骤 5:屏幕阅读器支持
确保屏幕阅读器体验良好:
图像替代文本:
<img src="logo.png" />
<img src="decorative.png" alt="decorative image" />
<img src="logo.png" alt="Company y Logo" />
<img src="decorative.png" alt="" role="presentation" />
图标按钮的 ARIA 标签:
<button><i class="icon-delete"></i></button>
<but tton aria-label="Delete item">
<i class="icon-delete" aria-hidden="true"></i>
</button>
动态内容的实时区域:
<div role="alert" aria-live="assertive">Error: Invalid email address</div>
<div aria-live="polite" aria-atomic="true">Loading results... 3 of 10 loaded</div>
步骤 6:表单无障碍
确保所有表单输入框均正确标注并经过验证:
要求:
- 所有输入框都有对应的
<label>元素 - 对分组输入框使用
<fieldset>和<legend> - 使用
aria-describedby显示验证错误 - 必填字段使用
aria-required="true"或required属性标记
示例:
<form>
<fieldset>
<legend>Personal Information</legend>
<label for="name">Name (required)</label>
<input id="name" type="textt" required aria-required="true" aria-describedby="name-error" />
<span id="name-error" role="alert" class="error" aria-live="polite">
</span>
<label for="email">Email</label>
<input id="email" type="email" aria-describedby="email-hint" />
<span id="email-hint" class="hint">We'll never share your email</span>
</fieldset>
</form>
步骤 7:生成无障碍报告
记录以下发现:
- 发现的问题总数(按严重程度分类)
- WCAG 等级合规状态(A、AA、AAA)
- 具体违规项及行号
- 建议的修复方法及代码示例
- 已执行的测试(自动化 + 手动)
示例 1:审查 React 组件
Skill({ skill: 'accessibility' });
输入:带有自定义模态框的 React 组件 输出:
- 语义化 HTML 建议
- 所需的 ARIA 属性
- 键盘导航问题
- 焦点陷阱实现
- WCAG 合规报告
示例 2:审核颜色对比度
Skill({ skill: 'accessibility', args: 'color-contrast' });
输入:包含颜色定义的 CSS 文件 输出:
- 对比度不合格项列表
- 建议的颜色调整
- 调整前后的对比度分数
示例 3:表单无障碍检查
Skill({ skill: 'accessibility', args: 'forms' });
输入:表单组件 输出:
- 已验证标签关联
- 必填字段指示
- 错误消息模式
- 键盘提交支持
<best_practices>
最佳实践
应该
- 使用语义化 HTML 作为基础(header、nav、main、article)
- 仅在语义化 HTML 不足时添加 ARIA
- 使用真实的屏幕阅读器进行测试(NVDA、JAWS、VoiceOver)
- 确保无需鼠标也能进行键盘导航
- 普通文本的对比度保持在 4.5:1(WCAG AA)
- 为所有非文本内容提供文本替代
- 使用焦点指示器(可见的 :focus-visible 样式)
- 将焦点限制在模态框内
- 使用 aria-live 播报动态内容
- 确保聚焦元素不会被粘性页眉/页脚遮挡(WCAG 2.2 2.4.11)
- 为所有拖拽交互提供键盘/点击替代方式(WCAG 2.2 2.5.7)
- 将所有指针目标的尺寸设为至少 24x24 CSS 像素(WCAG 2.2 2.5.8)
- 允许在密码字段中粘贴内容——绝不阻止粘贴(WCAG 2.2 3.3.8)
- 在多步骤流程中自动填充之前输入的数据(WCAG 2.2 3.3.7)
- 在各页面以一致的顺序放置帮助机制(WCAG 2.2 3.2.6)
不应该
- 所有内容都使用
<div>(没有语义) - 在非交互元素上添加点击处理程序
- 忘记为图像添加替代文本
- 仅依赖颜色传达信息
- 移除焦点指示器(outline: none)
- 在没有控件的情况下自动播放媒体
- 使用
tabindex> 0(会扰乱自然的 Tab 键顺序) - 创建键盘陷阱(用户无法退出)
- 向屏幕阅读器隐藏重要内容
反模式
| 反模式 | 问题 | 修复 |
|---|---|---|
<div onclick> | 无法通过键盘访问 | 使用 <button> |
| 没有替代文本 | 屏幕阅读器无法描述内容 | 添加有意义的 alt 属性 |
| 仅用颜色传达信息 | 色盲用户会错过信息 | 添加文本/图标 |
| 没有焦点指示器 | 用户在导航时容易迷失 | 添加 :focus-visible 样式 |
| 自动播放媒体 | 会干扰屏幕阅读器 | 添加控件和暂停选项 |
所有内容都使用 <div> | 缺少语义结构 | 使用语义化 HTML |
| 粘性页眉没有滚动外边距 | 焦点会被粘性栏遮挡(2.4.11) | 为 :focus-visible 添加 scroll-margin-top |
| 仅支持拖拽的可排序列表 | 有运动障碍的用户无法排序(2.5.7) | 为每个项目添加“上移”/“下移”按钮 |
| 16x16px 图标按钮 | 小于 24x24 最小目标尺寸(2.5.8) | 设置 min-width: 24px; min-height: 24px |
| CAPTCHA 没有替代方案 | 认证存在认知障碍(3.3.8) | 提供电子邮件魔法链接或通行密钥选项 |
onpaste="return false" | 阻止密码管理器粘贴(3.3.8) | 移除密码字段的粘贴限制 |
| 结账时重复填写表单字段 | 导致冗余数据录入(3.3.7) | 自动填充之前输入的值 |
测试清单
完成无障碍审查前:
WCAG 2.1 AA(现有要求):
- 所有图片都有替代文本(装饰性图片使用
alt="") - 所有交互元素都可通过键盘访问
- Tab 顺序合理
- 焦点指示器清晰可见
- 颜色对比度符合 WCAG AA(普通文本为 4.5:1,大号文本为 3:1)
- 使用语义化 HTML(nav、main、article 等)
- 图标按钮带有 ARIA 标签
- 表单带有恰当的标签
- 错误消息会播报给屏幕阅读器
- 对话框会锁定焦点,并可通过 Escape 关闭
- 动态内容使用 ARIA 实时区域
- 使用屏幕阅读器进行测试(NVDA、JAWS、VoiceOver)
- 仅使用键盘进行测试(不使用鼠标)
- 使用浏览器缩放进行测试(200%)
WCAG 2.2 AA(新增要求 — 2023 年 10 月,ISO/IEC 40500:2025):
- 2.4.11:固定页眉或页脚不会完全遮挡获得焦点的元素
- 2.5.7:所有拖动交互都提供单指针(点击/轻触)替代方式
- 2.5.8:所有指针目标至少为 24x24 CSS 像素
- 3.2.6:帮助方式(聊天、联系信息、电话)在各页面上的顺序一致
- 3.3.7:多步骤表单会自动填入先前输入的信息
- 3.3.8:身份验证不得要求用户完成认知能力测试(谜题/CAPTCHA),除非提供替代方式
- 密码字段允许粘贴(不得使用 onpaste="return false" 阻止粘贴)
- 设置焦点滚动边距,避免固定 UI 遮挡键盘焦点 </best_practices>
铁律
- 始终从语义化 HTML 开始 — 使用正确的原生元素(
<button>、<nav>、<main>等)之前,绝不要先使用 ARIA。 - 绝不移除焦点指示器 — 没有替代方案却使用
outline: none会立即违反 WCAG。键盘用户将完全无法确定焦点位置。 - 始终使用真实的辅助技术进行测试 — 自动化工具(axe、Lighthouse)最多只能发现 30% 的问题。必须使用 NVDA、JAWS 或 VoiceOver 进行测试。
- 绝不只通过颜色传达信息 — 对于色觉障碍用户,始终搭配文字、图标或图案来表示颜色。
- 始终遵循 WCAG 2.2 AA 标准 — 2.4.11(焦点不被遮挡)、2.5.7(拖动操作的替代方式)、2.5.8(24×24 的目标尺寸)、3.3.8(身份验证无认知障碍)均为强制要求,而非可选项。
集成点
使用此技能的 Agent
- developer:实现无障碍组件
- code-reviewer:审查 PR 中的无障碍问题
- qa:测试无障碍合规性
- frontend-pro:确保 UI 模式符合无障碍要求
- react-pro:React 专用无障碍模式
相关技能
- frontend-expert:UI 组件模式
- react-expert:React 无障碍模式
- mobile-first-design-rules:触控无障碍
工作流
- feature-development-workflow.md:在 Review 阶段进行无障碍审查
- code-review-workflow.md:无障碍检查清单
相关参考资料
.claude/rules/accessibility.md- 完整的无障碍规则- WCAG 2.2 指南(当前标准)
- WCAG 2.2 新增内容
- WCAG 2.2 快速参考
- WebAIM 对比度检查器
- ARIA 编写实践指南(APG)
- WCAG 2.2 完整实施指南(TestParty)
- 《欧洲无障碍法案》合规指南
记忆协议(强制)
开始前:
cat .claude/context/memory/learnings.md
检查以下内容:
- 之前发现的无障碍模式
- 此代码库中常见的无障碍问题
- 项目特定的无障碍要求
完成后:
- 新的无障碍模式 →
.claude/context/memory/learnings.md - 发现的无障碍问题 →
.claude/context/memory/issues.md - 做出的无障碍决策 →
.claude/context/memory/decisions.md
假设任务可能中断:你的上下文可能会重置。如果没有记录在记忆中,就等于没有发生。