Skill-style workflow for WCAG audits and accessibility fixes in web apps, covering automated scans, keyboard and screen reader checks, ARIA patterns and contrast.
Fill in variables
The prompt below and the copied text update as you type.
---
name: accessibility-testing-superpower
description: |
Performs WCAG compliance audits and accessibility remediation for web applications.
Use when: 1) Auditing UI for WCAG 2.1/2.2 compliance 2) Fixing screen reader or keyboard navigation issues 3) Implementing ARIA patterns correctly 4) Reviewing color contrast and visual accessibility 5) Creating accessible forms or interactive components
---
# Accessibility Testing Workflow
## Configuration
- **WCAG Level**: {{wcag_level}}
- **Component Under Test**: ${component_name:Page}
- **Compliance Standard**: {{compliance_standard}}
- **Minimum Lighthouse Score**: {{lighthouse_score}}
- **Primary Screen Reader**: {{screen_reader}}
- **Test Framework**: {{test_framework}}
## Audit Decision Tree
```
Accessibility request received
|
+-- New component/page?
| +-- Run automated scan first (axe-core, Lighthouse)
| +-- Keyboard navigation test
| +-- Screen reader announcement check
| +-- Color contrast verification
|
+-- Existing violation to fix?
| +-- Identify WCAG success criterion
| +-- Check if semantic HTML solves it
| +-- Apply ARIA only when HTML insufficient
| +-- Verify fix with assistive technology
|
+-- Compliance audit?
+-- Automated scan (catches ~30% of issues)
+-- Manual testing checklist
+-- Document violations by severity
+-- Create remediation roadmap
```
## WCAG Quick Reference
### Severity Classification
| Severity | Impact | Examples | Fix Timeline |
|----------|--------|----------|--------------|
| Critical | Blocks access entirely | No keyboard focus, empty buttons, missing alt on functional images | Immediate |
| Serious | Major barriers | Poor contrast, missing form labels, no skip links | Within sprint |
| Moderate | Difficult but usable | Inconsistent navigation, unclear error messages | Next release |
| Minor | Inconvenience | Redundant alt text, minor heading order issues | Backlog |
### Common Violations and Fixes
**Missing accessible name**
```html
<!-- Violation -->
<button><svg>...</svg></button>
<!-- Fix: aria-label -->
<button aria-label="Close dialog"><svg>...</svg></button>
<!-- Fix: visually hidden text -->
<button><span class="sr-only">Close dialog</span><svg>...</svg></button>
```
**Form label association**
```html
<!-- Violation -->
<label>Email</label>
<input type="email">
<!-- Fix: explicit association -->
<label for="email">Email</label>
<input type="email" id="email">
<!-- Fix: implicit association -->
<label>Email <input type="email"></label>
```
**Color contrast failure**
```
Minimum ratios (WCAG {{wcag_level}}):
- Normal text (<${large_text_size:18}px or <${bold_text_size:14}px bold): ${contrast_ratio_normal:4.5}:1
- Large text (>=${large_text_size:18}px or >=${bold_text_size:14}px bold): ${contrast_ratio_large:3}:1
- UI components and graphics: 3:1
Tools: WebAIM Contrast Checker, browser DevTools
```
**Focus visibility**
```css
/* Never do this without alternative */
:focus { outline: none; }
/* Proper custom focus */
:focus-visible {
outline: ${focus_outline_width:2}px solid ${focus_outline_color:#005fcc};
outline-offset: ${focus_outline_offset:2}px;
}
```
## ARIA Decision Framework
```
Need to convey information to assistive technology?
|
+-- Can semantic HTML do it?
| +-- YES: Use HTML (<button>, <nav>, <main>, <article>)
| +-- NO: Continue to ARIA
|
+-- What type of ARIA needed?
+-- Role: What IS this element? (role="dialog", role="tab")
+-- State: What condition? (aria-expanded, aria-checked)
+-- Property: What relationship? (aria-labelledby, aria-describedby)
+-- Live region: Dynamic content? (aria-live="${aria_live_mode:polite}")
```
### ARIA Patterns for Common Widgets
**Disclosure (show/hide)**
```html
<button aria-expanded="false" aria-controls="content-1">
Show details
</button>
<div id="content-1" hidden>
Content here
</div>
```
**Tab interface**
```html
<div role="tablist" aria-label="${component_name:Settings}">
<button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">
General
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
Privacy
</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">...</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>...</div>
```
**Modal dialog**
```html
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirm action</h2>
<p>Are you sure you want to proceed?</p>
<button>Cancel</button>
<button>Confirm</button>
</div>
```
## Keyboard Navigation Checklist
```
[ ] All interactive elements focusable with Tab
[ ] Focus order matches visual/logical order
[ ] Focus visible on all elements
[ ] No keyboard traps (can always Tab out)
[ ] Skip link as first focusable element
[ ] Escape closes modals/dropdowns
[ ] Arrow keys navigate within widgets (tabs, menus, grids)
[ ] Enter/Space activates buttons and links
[ ] Custom shortcuts documented and configurable
```
### Focus Management Patterns
**Modal focus trap**
```javascript
// On modal open:
// 1. Save previously focused element
// 2. Move focus to first focusable in modal
// 3. Trap Tab within modal boundaries
// On modal close:
// 1. Return focus to saved element
```
**Dynamic content**
```javascript
// After adding content:
// - Announce via aria-live region, OR
// - Move focus to new content heading
// After removing content:
// - Move focus to logical next element
// - Never leave focus on removed element
```
## Screen Reader Testing
### Announcement Verification
| Element | Should Announce |
|---------|-----------------|
| Button | Role + name + state ("Submit button") |
| Link | Name + "link" ("Home page link") |
| Image | Alt text OR "decorative" (skip) |
| Heading | Level + text ("Heading level 2, About us") |
| Form field | Label + type + state + instructions |
| Error | Error message + field association |
### Testing Commands (Quick Reference)
**VoiceOver (macOS)**
- VO = Ctrl + Option
- VO + A: Read all
- VO + Right/Left: Navigate elements
- VO + Cmd + H: Next heading
- VO + Cmd + J: Next form control
**{{screen_reader}} (Windows)**
- NVDA + Down: Read all
- Tab: Next focusable
- H: Next heading
- F: Next form field
- B: Next button
## Automated Testing Integration
### axe-core in tests
```javascript
// {{test_framework}}
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
test('${component_name:component} is accessible', async () => {
const { container } = render(<${component_name:MyComponent} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
```
### Lighthouse CI threshold
```javascript
// lighthouserc.js
module.exports = {
assertions: {
'categories:accessibility': ['error', { minScore: {{lighthouse_score}} / 100 }],
},
};
```
## Remediation Priority Matrix
```
Impact vs Effort:
Low Effort High Effort
High Impact | DO FIRST | PLAN NEXT |
| alt text | redesign |
| labels | nav rebuild |
----------------|--------------|---------------|
Low Impact | QUICK WIN | BACKLOG |
| contrast | nice-to-have|
| tweaks | enhancements|
```
## Verification Checklist
Before marking accessibility work complete:
```
Automated Testing:
[ ] axe-core reports zero violations
[ ] Lighthouse accessibility >= {{lighthouse_score}}
[ ] HTML validator passes (affects AT parsing)
Keyboard Testing:
[ ] Full task completion without mouse
[ ] Visible focus at all times
[ ] Logical tab order
[ ] No traps
Screen Reader Testing:
[ ] Tested with at least one screen reader ({{screen_reader}})
[ ] All content announced correctly
[ ] Interactive elements have roles/states
[ ] Dynamic updates announced
Visual Testing:
[ ] Contrast ratios verified (${contrast_ratio_normal:4.5}:1 minimum)
[ ] Works at ${zoom_level:200}% zoom
[ ] No information conveyed by color alone
[ ] Respects prefers-reduced-motion
```---
name: accessibility-testing-superpower
description: |
执行 Web 应用程序的 WCAG 合规性审计和无障碍修复。
使用场景:1) 对 UI 进行 WCAG 2.1/2.2 合规性审计 2) 修复屏幕阅读器或键盘导航问题 3) 正确实现 ARIA 模式 4) 审查颜色对比度和视觉无障碍性 5) 创建无障碍表单或交互式组件
---
# 无障碍测试工作流
## 配置
- **WCAG 级别**: {{wcag_level}}
- **被测组件**: ${component_name:Page}
- **合规标准**: {{compliance_standard}}
- **最低 Lighthouse 分数**: {{lighthouse_score}}
- **主要屏幕阅读器**: {{screen_reader}}
- **测试框架**: {{test_framework}}
## 审计决策树
```
收到无障碍请求
|
+-- 新组件/页面?
| +-- 首先运行自动化扫描(axe-core, Lighthouse)
| +-- 键盘导航测试
| +-- 屏幕阅读器播报检查
| +-- 颜色对比度验证
|
+-- 存在需修复的现有违规?
| +-- 确定对应的 WCAG 成功准则
| +-- 检查语义化 HTML 是否可解决
| +-- 仅在 HTML 不足时应用 ARIA
| +-- 使用辅助技术验证修复效果
|
+-- 合规性审计?
+-- 自动化扫描(可捕获约 30% 的问题)
+-- 手动测试清单
+-- 按严重性记录违规项
+-- 创建修复路线图
```
## WCAG 快速参考
### 严重性分类
| 严重性 | 影响 | 示例 | 修复时间线 |
|----------|--------|----------|--------------|
| 致命 | 完全阻碍访问 | 无键盘焦点、空按钮、功能性图像缺少 alt | 立即 |
| 严重 | 重大障碍 | 对比度差、缺少表单标签、无跳过链接 | 本迭代内 |
| 中等 | 使用困难但仍可用 | 导航不一致、错误信息不明确 | 下一版本 |
| 轻微 | 使用不便 | 冗余的 alt 文本、轻微的标题层级问题 | 待办事项 |
### 常见违规及修复方法
**缺少可访问名称**
```html
<!-- 违规 -->
<button><svg>...</svg></button>
<!-- 修复:aria-label -->
<button aria-label="关闭对话框"><svg>...</svg></button>
<!-- 修复:视觉隐藏文本 -->
<button><span class="sr-only">关闭对话框</span><svg>...</svg></button>
```
**表单标签关联**
```html
<!-- 违规 -->
<label>邮箱</label>
<input type="email">
<!-- 修复:显式关联 -->
<label for="email">邮箱</label>
<input type="email" id="email">
<!-- 修复:隐式关联 -->
<label>邮箱 <input type="email"></label>
```
**颜色对比度不达标**
```
最低对比度比例(WCAG {{wcag_level}}):
- 普通文本(<${large_text_size:18}px 或 <${bold_text_size:14}px 加粗):${contrast_ratio_normal:4.5}:1
- 大号文本(>=${large_text_size:18}px 或 >=${bold_text_size:14}px 加粗):${contrast_ratio_large:3}:1
- UI 组件和图形:3:1
工具:WebAIM Contrast Checker、浏览器 DevTools
```
**焦点可见性**
```css
/* 不提供替代方案时切勿这样做 */
:focus { outline: none; }
/* 正确的自定义焦点样式 */
:focus-visible {
outline: ${focus_outline_width:2}px solid ${focus_outline_color:#005fcc};
outline-offset: ${focus_outline_offset:2}px;
}
```
### 焦点管理模式
**模态框焦点陷阱**
```javascript
// 模态框打开时:
// 1. 保存之前获得焦点的元素
// 2. 将焦点移动到模态框内第一个可聚焦元素
// 3. 将 Tab 键限制在模态框边界内
// 模态框关闭时:
// 1. 将焦点返回至已保存的元素
```
**动态内容**
```javascript
// 添加内容后:
// - 通过 aria-live 区域宣布,或
// - 将焦点移至新内容的标题
// 删除内容后:
// - 将焦点移至逻辑上的下一个元素
// - 绝不能让焦点停留在已被删除的元素上
```
## 屏幕阅读器测试
### 宣告内容验证
| 元素 | 应当宣告的内容 |
|---------|-----------------|
| 按钮 | 角色 + 名称 + 状态(例如“提交按钮”) |
| 链接 | 名称 + “link”(例如“首页链接”) |
| 图像 | 替代文本 或 “decorative”(跳过) |
| 标题 | 级别 + 文本(例如“二级标题,关于我们”) |
| 表单字段 | 标签 + 类型 + 状态 + 说明 |
| 错误 | 错误信息 + 关联字段 |
### 测试命令(快速参考)
**VoiceOver (macOS)**
- VO = Ctrl + Option
- VO + A:朗读全部
- VO + Right/Left:在元素间导航
- VO + Cmd + H:下一个标题
- VO + Cmd + J:下一个表单控件
**{{screen_reader}} (Windows)**
- NVDA + Down:朗读全部
- Tab:下一个可聚焦元素
- H:下一个标题
- F:下一个表单字段
- B:下一个按钮
## 自动化测试集成
### 在测试中使用 axe-core
```javascript
// {{test_framework}}
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
test('${component_name:component} 是无障碍的', async () => {
const { container } = render(<${component_name:MyComponent} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
```
### Lighthouse CI 门槛设置
```javascript
// lighthouserc.js
module.exports = {
assertions: {
'categories:accessibility': ['error', { minScore: {{lighthouse_score}} / 100 }],
},
};
```
## 修复优先级矩阵
```
影响 vs 努力:
低努力 高努力
高影响 | 优先处理 | 计划后续 |
| 替代文本 | 重新设计 |
| 标签 | 导航重构 |
-----------------|---------------|-------------|
低影响 | 快速胜利 | 待办清单 |
| 对比度调整 | 可选优化 |
| | 增强功能 |
```
## 验证清单
在标记无障碍工作完成前:
```
自动化测试:
[ ] axe-core 报告零违规
[ ] Lighthouse 无障碍分数 >= {{lighthouse_score}}
[ ] HTML 验证通过(影响辅助技术解析)
键盘测试:
[ ] 不使用鼠标即可完成全部任务
[ ] 始终可见焦点
[ ] Tab 键顺序符合逻辑
[ ] 无焦点陷阱
屏幕阅读器测试:
[ ] 至少使用一种屏幕阅读器进行测试 ({{screen_reader}})
[ ] 所有内容均被正确宣告
[ ] 交互元素具有正确的角色/状态
[ ] 动态更新被正确宣告
视觉测试:
[ ] 已验证对比度比率 (${contrast_ratio_normal:4.5}:1 最低要求)
[ ] 在 ${zoom_level:200}% 缩放下正常工作
[ ] 无仅通过颜色传达的信息
[ ] 尊重 prefers-reduced-motion 设置
```