无障碍专家
Accessibility Expert
测试并修复无障碍问题,以符合 WCAG 标准和辅助技术兼容性。适用于 (1) 审计 UI 的无障碍违规问题。
适用平台:
ChatGPTClaudeGemini
---
name: accessibility-expert
description: 测试并修复可访问性问题,以符合 WCAG 标准和辅助技术兼容性。在以下情况下使用:(1) 审计 UI 中的可访问性违规,(2) 实现键盘导航或屏幕阅读器支持,(3) 修复颜色对比度或焦点指示器问题,(4) 确保表单可访问性和错误处理,(5) 创建 ARIA 实现。
---
# 可访问性测试与修复
## 配置
- **WCAG 等级**: ${wcag_level:AA}
- **目标组件**: ${component_name:Application}
- **合规标准**: ${compliance_standard:WCAG 2.1}
- **测试范围**: ${testing_scope:full-audit}
- **屏幕阅读器**: ${screen_reader:NVDA}
## WCAG 2.1 快速参考
### 合规等级
| 等级 | 要求 | 常见问题 |
|-------|-------------|---------------|
| A | 最低基线 | 缺少替代文本,无键盘访问,缺少表单标签 |
| ${wcag_level:AA} | 标准目标 | 对比度 < 4.5:1,缺少焦点指示器,标题结构不佳 |
| AAA | 增强 | 对比度 < 7:1,手语,扩展音频描述 |
### 四项原则 (POUR)
1. **可感知**: 内容可被感官获取(替代文本、字幕、对比度)
2. **可操作**: UI 可通过所有输入方法导航(键盘、触摸、语音)
3. **可理解**: 内容和 UI 可预测且可读
4. **鲁棒**: 适用于当前和未来的辅助技术
## 违规严重性矩阵
```
严重 (立即修复):
- 交互元素无键盘访问
- 缺少表单标签
- 无替代文本的图片
- 无控件的自动播放音频
- 键盘陷阱
高(发布前修复):
- 对比度低于 ${min_contrast_ratio:4.5}:1(文本)或 3:1(大文本)
- 缺少跳过链接
- 标题层级不正确
- 焦点不可见
- 缺少错误识别
中(下个冲刺修复):
- 导航不一致
- 缺少地标
- 链接文本不佳(“点击此处”)
- 缺少语言属性
- 没有标题的复杂表格
低(待办事项):
- 时间调整
- 查找内容的多种方式
- 上下文相关帮助
```
## 测试决策树
```
开始:您正在测试什么?
|
+-- 新组件
| +-- 有交互元素吗? --> 键盘导航清单
| +-- 有文本内容吗? --> 检查对比度 + 标题结构
| +-- 有图片吗? --> 验证 alt 文本的适当性
| +-- 有表单吗? --> 表单可访问性清单
|
+-- 现有页面/功能
| +-- 首先运行自动化扫描(axe-core, Lighthouse)
| +-- 手动键盘遍历
| +-- 屏幕阅读器验证
| +-- 颜色对比度抽查
|
+-- 第三方小部件
+-- 检查 ARIA 实现
+-- 验证键盘支持
+-- 使用屏幕阅读器测试
+-- 记录限制
```
## 键盘导航清单
```markdown
[ ] 所有交互元素都可以通过 Tab 键访问
[ ] Tab 键顺序遵循视觉/逻辑流
[ ] 焦点指示器可见(${focus_indicator_width:2}px+ 轮廓,3:1 对比度)
[ ] 没有键盘陷阱(可以 Tab 键离开所有元素)
[ ] 跳过链接作为第一个可聚焦元素
[ ] Enter 键激活按钮和链接
[ ] Space 键激活复选框和按钮
[ ] 方向键在组件内导航(选项卡、菜单、单选组)
[ ] Escape 键关闭模态框和下拉菜单
[ ] 模态框在关闭前捕获焦点
```
## 屏幕阅读器测试模式
### 需要验证的重要公告
```
交互元素:
按钮:"[标签], 按钮"
链接:"[文本], 链接"
复选框:"[标签], 复选框, [已选中/未选中]"
单选按钮:"[标签], 单选按钮, [已选中], [位置] 共 [总数]"
组合框:"[标签], 组合框, [已折叠/已展开]"
动态内容:
加载中:在容器上使用 aria-busy="true"
状态:对于非关键更新使用 role="status"
警报:对于关键消息使用 role="alert"
实时区域:aria-live="${aria_live_politeness:polite}"
表单:
必填项:与标签一起宣布“必填”
无效项:与错误消息一起宣布“无效输入”
说明:通过 aria-describedby 与标签一起宣布
```
### 测试顺序
1. 使用 Tab 键浏览整个页面,听取公告
2. 测试标题导航(屏幕阅读器中的 H 键)
3. 测试地标导航(D 键 / 转子)
4. 测试表格(T 键,表格内的箭头键)
5. 测试表单(F 键,完成表单提交)
6. 测试动态内容更新(验证实时区域)
## 颜色对比度要求
| 文本类型 | 最小对比度 | 增强(AAA) |
|-----------|---------------|----------------|
| 常规文本(<${large_text_threshold:18}pt) | ${min_contrast_ratio:4.5}:1 | 7:1 |
| 大文本(>=${large_text_threshold:18}pt 或 14pt 粗体) | 3:1 | 4.5:1 |
| UI 组件和图形 | 3:1 | 不适用 |
| 焦点指示器 | 3:1 | 不适用 |
### 对比度检查流程
```
1. 识别所有前景/背景颜色对
2. 计算对比度:(L1 + 0.05) / (L2 + 0.05)
其中 L1 = 较亮亮度,L2 = 较暗亮度
3. 常见检查失败项:
- 占位符文本(通常太亮)
- 禁用状态(豁免但考虑可用性)
- 文本中的链接(必须与文本区分开)
- 彩色背景上的错误/成功状态
- 图像上的文本(使用叠加层或文本阴影)
```
## ARIA 实现指南
### ARIA 第一原则
尽可能使用原生 HTML 元素。ARIA 仅用于自定义小部件。
```html
<!-- 错误:在原生元素上使用 ARIA -->
<div role="button" tabindex="0">Submit</div>
<!-- 正确:原生按钮 -->
<button type="submit">Submit</button>
```
### 何时需要 ARIA
```html
<!-- 自定义选项卡 -->
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel1">Tab 1</button>
<button role="tab" aria-selected="false" aria-controls="panel2">Tab 2</button>
</div>
<div role="tabpanel" id="panel1">Content 1</div>
<div role="tabpanel" id="panel2" hidden>Content 2</div>
<!-- 可展开部分 -->
<button aria-expanded="false" aria-controls="content">Show details</button>
<div id="content" hidden>Expandable content</div>
<!-- 模态对话框 -->
<div role="dialog" aria-modal="true" aria-labelledby="title">
<h2 id="title">Dialog Title</h2>
<!-- content -->
</div>
<!-- 用于动态更新的实时区域 -->
<div aria-live="${aria_live_politeness:polite}" aria-atomic="true">
<!-- 状态消息注入此处 -->
</div>
```
### 常见的 ARIA 错误
```
- role="button" 但无键盘支持(回车/空格)
- aria-label 重复可见文本
- aria-hidden="true" 用于可聚焦元素
- 披露按钮缺少 aria-expanded
- aria-controls 引用不正确
- 使用 aria-describedby 描述必要信息
```
## 表单可访问性模式
### 必需的表单结构
```html
<form>
<!-- 明确的标签关联 -->
<label for="email">电子邮件地址</label>
<input type="email" id="email" name="email"
aria-required="true"
aria-describedby="email-hint email-error">
<span id="email-hint">我们绝不会分享您的电子邮件</span>
<span id="email-error" role="alert"></span>
<!-- 组合相关字段 -->
<fieldset>
<legend>收货地址</legend>
<!-- 地址字段 -->
</fieldset>
<!-- 清晰的提交按钮 -->
<button type="submit">完成订单</button>
</form>
```
### 错误处理要求
```
1. 识别出错字段(高亮 + 图标)
2. 用文本描述错误(不只是颜色)
3. 将错误与字段关联(aria-describedby)
4. 向屏幕阅读器宣布错误(role="alert")
5. 提交失败时将焦点移至第一个错误
6. 尽可能提供更正建议
```
## 移动端可访问性清单
```markdown
触摸目标:
[ ] 最小 ${touch_target_size:44}x${touch_target_size:44} CSS 像素
[ ] 目标之间有足够的间距(${touch_target_spacing:8}px+)
[ ] 触摸操作不依赖于手势路径
手势:
[ ] 多指手势的替代方案
[ ] 基于路径手势(滑动)的替代方案
[ ] 基于动作的操作有替代方案
```
屏幕阅读器 (iOS/Android):
[ ] 图像和图标设置了 accessibilityLabel
[ ] 复杂交互设置了 accessibilityHint
[ ] accessibilityRole 与元素行为匹配
[ ] 焦点顺序遵循视觉布局
```
## 自动化测试集成
### 预提交钩子
```bash
#!/bin/bash
# 对更改的文件运行 axe-core
npx axe-core-cli --exit src/**/*.html
# 检查常见问题
grep -r "onClick.*div\|onClick.*span" src/ && \
echo "警告:在非交互元素上存在点击处理程序" && exit 1
```
### CI 流水线检查
```yaml
accessibility-audit:
script:
- npx pa11y-ci --config .pa11yci.json
- npx lighthouse --accessibility --output=json
artifacts:
paths:
- accessibility-report.json
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
```
### 最低 CI 阈值
```
axe-core: 0 个严重违规,0 个主要违规
Lighthouse 可访问性: >= ${lighthouse_a11y_threshold:90}
pa11y: 0 个错误 (警告可接受)
```
## 修复优先级框架
```
优先级 1 (本 Sprint):
- 阻碍用户任务完成
- 法律合规风险
- 影响大量用户
优先级 2 (下个 Sprint):
- 显著降低用户体验
- 自动化工具标记为错误
- 违反 ${wcag_level:AA} 要求
优先级 3 (待办事项):
- 轻微不便
- 仅违反 AAA
- 影响边缘情况
优先级 4 (增强):
- 改善所有用户的可用性
- 最佳实践,而非要求
- 面向未来
```
## 验证清单
在标记可访问性工作完成之前:
```markdown
自动化:
[ ] axe-core: 0 个违规
[ ] Lighthouse 可访问性: ${lighthouse_a11y_threshold:90}+
[ ] HTML 验证通过
[ ] 无控制台可访问性警告
键盘:
[ ] 仅使用键盘完成所有任务
[ ] 焦点始终可见
[ ] Tab 键顺序符合逻辑
[ ] 无键盘陷阱
屏幕阅读器(至少测试一个):
[ ] 所有内容均可播报
[ ] 交互元素已标记
[ ] 错误和更新已播报
[ ] 导航高效
视觉:
[ ] 所有文本通过对比度检查
[ ] UI 组件通过对比度检查
[ ] 在 ${zoom_level:200}% 缩放下正常工作
[ ] 在高对比度模式下正常工作
[ ] 无引起癫痫发作的闪烁
表单:
[ ] 所有字段均已标记
[ ] 错误可识别
[ ] 必填字段已标明
[ ] 提供说明
```
## 文档模板
```markdown
# 可访问性声明
## 符合性状态
本[网站/应用程序] [完全/部分] 符合 ${compliance_standard:WCAG 2.1} ${wcag_level:AA} 级别。
## 已知限制
| 功能 | 问题 | 变通方法 | 时间线 |
|---------|-------|------------|----------|
| [功能] | [描述] | [替代方案] | [修复日期] |
## 已测试的辅助技术
- ${screen_reader:NVDA} [版本] 与 Firefox [版本]
- VoiceOver 与 Safari [版本]
- JAWS [版本] 与 Chrome [版本]
## 反馈
有关可访问性问题,请联系 [电子邮件]。
最后更新:[日期]
```