wcag-audit-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWCAG Audit Patterns
WCAG审计模式
Comprehensive guide to auditing web content against WCAG 2.2 guidelines with actionable remediation strategies.
针对WCAG 2.2指南的网页内容综合审计指南,附可行的修复策略。
When to Use This Skill
何时使用此技能
- Conducting accessibility audits
- Fixing WCAG violations
- Implementing accessible components
- Preparing for accessibility lawsuits
- Meeting ADA/Section 508 requirements
- Achieving VPAT compliance
- 开展无障碍审计
- 修复WCAG违规问题
- 实现无障碍组件
- 为无障碍诉讼做准备
- 满足ADA/Section 508要求
- 达成VPAT合规
Core Concepts
核心概念
1. WCAG Conformance Levels
1. WCAG合规等级
| Level | Description | Required For |
|---|---|---|
| A | Minimum accessibility | Legal baseline |
| AA | Standard conformance | Most regulations |
| AAA | Enhanced accessibility | Specialized needs |
| 等级 | 描述 | 适用场景 |
|---|---|---|
| A | 最低无障碍要求 | 法律基线 |
| AA | 标准合规 | 大多数法规要求 |
| AAA | 增强型无障碍 | 特殊需求场景 |
2. POUR Principles
2. POUR原则
Perceivable: Can users perceive the content?
Operable: Can users operate the interface?
Understandable: Can users understand the content?
Robust: Does it work with assistive tech?Perceivable: Can users perceive the content?
Operable: Can users operate the interface?
Understandable: Can users understand the content?
Robust: Does it work with assistive tech?3. Common Violations by Impact
3. 常见违规问题按影响程度分类
Critical (Blockers):
├── Missing alt text for functional images
├── No keyboard access to interactive elements
├── Missing form labels
└── Auto-playing media without controls
Serious:
├── Insufficient color contrast
├── Missing skip links
├── Inaccessible custom widgets
└── Missing page titles
Moderate:
├── Missing language attribute
├── Unclear link text
├── Missing landmarks
└── Improper heading hierarchyCritical (Blockers):
├── Missing alt text for functional images
├── No keyboard access to interactive elements
├── Missing form labels
└── Auto-playing media without controls
Serious:
├── Insufficient color contrast
├── Missing skip links
├── Inaccessible custom widgets
└── Missing page titles
Moderate:
├── Missing language attribute
├── Unclear link text
├── Missing landmarks
└── Improper heading hierarchyAudit Checklist
审计检查清单
Perceivable (Principle 1)
可感知性(原则1)
markdown
undefinedmarkdown
undefined1.1 Text Alternatives
1.1 文本替代方案
1.1.1 Non-text Content (Level A)
1.1.1 非文本内容(A级)
- All images have alt text
- Decorative images have alt=""
- Complex images have long descriptions
- Icons with meaning have accessible names
- CAPTCHAs have alternatives
Check:
html
<!-- Good -->
<img src="chart.png" alt="Sales increased 25% from Q1 to Q2" />
<img src="decorative-line.png" alt="" />
<!-- Bad -->
<img src="chart.png" />
<img src="decorative-line.png" alt="decorative line" />undefined- 所有图片均有替代文本(alt text)
- 装饰性图片使用alt=""
- 复杂图片配有详细描述
- 具有含义的图标配有可访问名称
- CAPTCHA提供替代方案
检查示例:
html
<!-- Good -->
<img src="chart.png" alt="Sales increased 25% from Q1 to Q2" />
<img src="decorative-line.png" alt="" />
<!-- Bad -->
<img src="chart.png" />
<img src="decorative-line.png" alt="decorative line" />undefined1.2 Time-based Media
1.2 基于时间的媒体
1.2.1 Audio-only and Video-only (Level A)
1.2.1 仅音频和仅视频内容(A级)
- Audio has text transcript
- Video has audio description or transcript
- 音频配有文字转录稿
- 视频配有音频描述或转录稿
1.2.2 Captions (Level A)
1.2.2 字幕(A级)
- All video has synchronized captions
- Captions are accurate and complete
- Speaker identification included
- 所有视频配有同步字幕
- 字幕准确完整
- 包含说话人标识
1.2.3 Audio Description (Level A)
1.2.3 音频描述(A级)
- Video has audio description for visual content
- 视频为视觉内容提供音频描述
1.3 Adaptable
1.3 可适应性
1.3.1 Info and Relationships (Level A)
1.3.1 信息与关系(A级)
- Headings use proper tags (h1-h6)
- Lists use ul/ol/dl
- Tables have headers
- Form inputs have labels
- ARIA landmarks present
Check:
html
<!-- Heading hierarchy -->
<h1>Page Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
<h2>Another Section</h2>
<!-- Table headers -->
<table>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Price</th>
</tr>
</thead>
</table>- 标题使用正确的标签(h1-h6)
- 列表使用ul/ol/dl标签
- 表格配有表头
- 表单输入项配有标签
- 存在ARIA地标
检查示例:
html
<!-- Heading hierarchy -->
<h1>Page Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
<h2>Another Section</h2>
<!-- Table headers -->
<table>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Price</th>
</tr>
</thead>
</table>1.3.2 Meaningful Sequence (Level A)
1.3.2 有意义的顺序(A级)
- Reading order is logical
- CSS positioning doesn't break order
- Focus order matches visual order
- 阅读顺序符合逻辑
- CSS定位不破坏顺序
- 焦点顺序与视觉顺序一致
1.3.3 Sensory Characteristics (Level A)
1.3.3 感官特性(A级)
- Instructions don't rely on shape/color alone
- "Click the red button" → "Click Submit (red button)"
- 操作说明不单独依赖形状/颜色
- 避免“点击红色按钮”,改为“点击提交(红色按钮)”
1.4 Distinguishable
1.4 可区分性
1.4.1 Use of Color (Level A)
1.4.1 颜色的使用(A级)
- Color is not only means of conveying info
- Links distinguishable without color
- Error states not color-only
- 不单独使用颜色传递信息
- 链接无需依赖颜色即可区分
- 错误状态不单独通过颜色标识
1.4.3 Contrast (Minimum) (Level AA)
1.4.3 对比度(最低要求)(AA级)
- Text: 4.5:1 contrast ratio
- Large text (18pt+): 3:1 ratio
- UI components: 3:1 ratio
Tools: WebAIM Contrast Checker, axe DevTools
- 文本对比度达到4.5:1
- 大文本(18pt及以上)对比度达到3:1
- UI组件对比度达到3:1
工具:WebAIM对比度检查器、axe DevTools
1.4.4 Resize Text (Level AA)
1.4.4 文本缩放(AA级)
- Text resizes to 200% without loss
- No horizontal scrolling at 320px
- Content reflows properly
- 文本可缩放至200%且无内容丢失
- 在320px宽度下无水平滚动
- 内容可正确重排
1.4.10 Reflow (Level AA)
1.4.10 重排(AA级)
- Content reflows at 400% zoom
- No two-dimensional scrolling
- All content accessible at 320px width
- 内容在400%缩放时可重排
- 无二维滚动
- 在320px宽度下所有内容均可访问
1.4.11 Non-text Contrast (Level AA)
1.4.11 非文本对比度(AA级)
- UI components have 3:1 contrast
- Focus indicators visible
- Graphical objects distinguishable
- UI组件对比度达到3:1
- 焦点指示器可见
- 图形对象可区分
1.4.12 Text Spacing (Level AA)
1.4.12 文本间距(AA级)
- No content loss with increased spacing
- Line height 1.5x font size
- Paragraph spacing 2x font size
- Letter spacing 0.12x font size
- Word spacing 0.16x font size
undefined- 增加间距后无内容丢失
- 行高为字体大小的1.5倍
- 段落间距为字体大小的2倍
- 字母间距为字体大小的0.12倍
- 单词间距为字体大小的0.16倍
undefinedOperable (Principle 2)
可操作性(原则2)
markdown
undefinedmarkdown
undefined2.1 Keyboard Accessible
2.1 键盘可访问性
2.1.1 Keyboard (Level A)
2.1.1 键盘操作(A级)
- All functionality keyboard accessible
- No keyboard traps
- Tab order is logical
- Custom widgets are keyboard operable
Check:
javascript
// Custom button must be keyboard accessible
<div role="button" tabindex="0"
onkeydown="if(event.key === 'Enter' || event.key === ' ') activate()">- 所有功能均可通过键盘访问
- 无键盘陷阱
- Tab键顺序符合逻辑
- 自定义组件可通过键盘操作
检查示例:
javascript
// Custom button must be keyboard accessible
<div role="button" tabindex="0"
onkeydown="if(event.key === 'Enter' || event.key === ' ') activate()">2.1.2 No Keyboard Trap (Level A)
2.1.2 无键盘陷阱(A级)
- Focus can move away from all components
- Modal dialogs trap focus correctly
- Focus returns after modal closes
- 焦点可从所有组件移出
- 模态对话框正确捕获焦点
- 模态框关闭后焦点返回原位置
2.2 Enough Time
2.2 充足的时间
2.2.1 Timing Adjustable (Level A)
2.2.1 可调整计时(A级)
- Session timeouts can be extended
- User warned before timeout
- Option to disable auto-refresh
- 会话超时可延长
- 超时前向用户发出警告
- 可禁用自动刷新
2.2.2 Pause, Stop, Hide (Level A)
2.2.2 暂停、停止、隐藏(A级)
- Moving content can be paused
- Auto-updating content can be paused
- Animations respect prefers-reduced-motion
css
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}- 动态内容可暂停
- 自动更新内容可暂停
- 动画尊重prefers-reduced-motion设置
css
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}2.3 Seizures and Physical Reactions
2.3 癫痫发作和身体反应
2.3.1 Three Flashes (Level A)
2.3.1 三次闪烁(A级)
- No content flashes more than 3 times/second
- Flashing area is small (<25% viewport)
- 内容闪烁频率不超过每秒3次
- 闪烁区域小于视口的25%
2.4 Navigable
2.4 可导航性
2.4.1 Bypass Blocks (Level A)
2.4.1 绕过重复区块(A级)
- Skip to main content link present
- Landmark regions defined
- Proper heading structure
html
<a href="#main" class="skip-link">Skip to main content</a>
<main id="main">...</main>- 存在“跳转到主要内容”链接
- 定义了地标区域
- 标题结构合理
html
<a href="#main" class="skip-link">Skip to main content</a>
<main id="main">...</main>2.4.2 Page Titled (Level A)
2.4.2 页面标题(A级)
- Unique, descriptive page titles
- Title reflects page content
- 页面标题唯一且具有描述性
- 标题反映页面内容
2.4.3 Focus Order (Level A)
2.4.3 焦点顺序(A级)
- Focus order matches visual order
- tabindex used correctly
- 焦点顺序与视觉顺序一致
- 正确使用tabindex
2.4.4 Link Purpose (In Context) (Level A)
2.4.4 链接用途(上下文内)(A级)
- Links make sense out of context
- No "click here" or "read more" alone
html
<!-- Bad -->
<a href="report.pdf">Click here</a>
<!-- Good -->
<a href="report.pdf">Download Q4 Sales Report (PDF)</a>- 链接脱离上下文仍有明确含义
- 避免单独使用“点击这里”或“阅读更多”
html
<!-- Bad -->
<a href="report.pdf">Click here</a>
<!-- Good -->
<a href="report.pdf">Download Q4 Sales Report (PDF)</a>2.4.6 Headings and Labels (Level AA)
2.4.6 标题与标签(AA级)
- Headings describe content
- Labels describe purpose
- 标题准确描述内容
- 标签准确说明用途
2.4.7 Focus Visible (Level AA)
2.4.7 可见焦点(AA级)
- Focus indicator visible on all elements
- Custom focus styles meet contrast
css
:focus {
outline: 3px solid #005fcc;
outline-offset: 2px;
}- 所有元素的焦点指示器可见
- 自定义焦点样式符合对比度要求
css
:focus {
outline: 3px solid #005fcc;
outline-offset: 2px;
}2.4.11 Focus Not Obscured (Level AA) - WCAG 2.2
2.4.11 焦点不被遮挡(AA级)- WCAG 2.2
- Focused element not fully hidden
- Sticky headers don't obscure focus
undefined- 获得焦点的元素不会被完全遮挡
- 粘性页眉不会遮挡焦点
undefinedUnderstandable (Principle 3)
可理解性(原则3)
markdown
undefinedmarkdown
undefined3.1 Readable
3.1 可读性
3.1.1 Language of Page (Level A)
3.1.1 页面语言(A级)
- HTML lang attribute set
- Language correct for content
html
<html lang="en">- 设置了HTML lang属性
- 语言与内容匹配
html
<html lang="en">3.1.2 Language of Parts (Level AA)
3.1.2 局部内容语言(AA级)
- Language changes marked
html
<p>The French word <span lang="fr">bonjour</span> means hello.</p>- 语言变化处有标识
html
<p>The French word <span lang="fr">bonjour</span> means hello.</p>3.2 Predictable
3.2 可预测性
3.2.1 On Focus (Level A)
3.2.1 聚焦时(A级)
- No context change on focus alone
- No unexpected popups on focus
- 仅聚焦操作不会导致上下文变化
- 聚焦时不会弹出意外窗口
3.2.2 On Input (Level A)
3.2.2 输入时(A级)
- No automatic form submission
- User warned before context change
- 无自动表单提交
- 上下文变化前向用户发出警告
3.2.3 Consistent Navigation (Level AA)
3.2.3 导航一致性(AA级)
- Navigation consistent across pages
- Repeated components same order
- 导航在所有页面保持一致
- 重复组件顺序相同
3.2.4 Consistent Identification (Level AA)
3.2.4 标识一致性(AA级)
- Same functionality = same label
- Icons used consistently
- 相同功能使用相同标签
- 图标使用保持一致
3.3 Input Assistance
3.3 输入辅助
3.3.1 Error Identification (Level A)
3.3.1 错误识别(A级)
- Errors clearly identified
- Error message describes problem
- Error linked to field
html
<input aria-describedby="email-error" aria-invalid="true" />
<span id="email-error" role="alert">Please enter valid email</span>- 错误被清晰标识
- 错误消息描述问题
- 错误与对应字段关联
html
<input aria-describedby="email-error" aria-invalid="true" />
<span id="email-error" role="alert">Please enter valid email</span>3.3.2 Labels or Instructions (Level A)
3.3.2 标签或说明(A级)
- All inputs have visible labels
- Required fields indicated
- Format hints provided
- 所有输入项均有可见标签
- 必填字段有明确标识
- 提供格式提示
3.3.3 Error Suggestion (Level AA)
3.3.3 错误建议(AA级)
- Errors include correction suggestion
- Suggestions are specific
- 错误提示包含修正建议
- 建议具体明确
3.3.4 Error Prevention (Level AA)
3.3.4 错误预防(AA级)
- Legal/financial forms reversible
- Data checked before submission
- User can review before submit
undefined- 法律/金融表单可撤销
- 提交前检查数据
- 用户可在提交前复查内容
undefinedRobust (Principle 4)
健壮性(原则4)
markdown
undefinedmarkdown
undefined4.1 Compatible
4.1 兼容性
4.1.1 Parsing (Level A) - Obsolete in WCAG 2.2
4.1.1 解析(A级)- WCAG 2.2中已废弃
- Valid HTML (good practice)
- No duplicate IDs
- Complete start/end tags
- 使用有效的HTML(最佳实践)
- 无重复ID
- 标签完整闭合
4.1.2 Name, Role, Value (Level A)
4.1.2 名称、角色、值(A级)
- Custom widgets have accessible names
- ARIA roles correct
- State changes announced
html
<!-- Accessible custom checkbox -->
<div role="checkbox"
aria-checked="false"
tabindex="0"
aria-labelledby="label">
</div>
<span id="label">Accept terms</span>- 自定义组件具有可访问名称
- ARIA角色正确
- 状态变化可被辅助技术识别
html
<!-- Accessible custom checkbox -->
<div role="checkbox"
aria-checked="false"
tabindex="0"
aria-labelledby="label">
</div>
<span id="label">Accept terms</span>4.1.3 Status Messages (Level AA)
4.1.3 状态消息(AA级)
- Status updates announced
- Live regions used correctly
html
<div role="status" aria-live="polite">3 items added to cart</div>
<div role="alert" aria-live="assertive">Error: Form submission failed</div>undefined- 状态更新可被辅助技术播报
- 正确使用实时区域(live regions)
html
<div role="status" aria-live="polite">3 items added to cart</div>
<div role="alert" aria-live="assertive">Error: Form submission failed</div>undefinedAutomated Testing
自动化测试
javascript
// axe-core integration
const axe = require('axe-core');
async function runAccessibilityAudit(page) {
await page.addScriptTag({ path: require.resolve('axe-core') });
const results = await page.evaluate(async () => {
return await axe.run(document, {
runOnly: {
type: 'tag',
values: ['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']
}
});
});
return {
violations: results.violations,
passes: results.passes,
incomplete: results.incomplete
};
}
// Playwright test example
test('should have no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await runAccessibilityAudit(page);
expect(results.violations).toHaveLength(0);
});bash
undefinedjavascript
// axe-core integration
const axe = require('axe-core');
async function runAccessibilityAudit(page) {
await page.addScriptTag({ path: require.resolve('axe-core') });
const results = await page.evaluate(async () => {
return await axe.run(document, {
runOnly: {
type: 'tag',
values: ['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']
}
});
});
return {
violations: results.violations,
passes: results.passes,
incomplete: results.incomplete
};
}
// Playwright test example
test('should have no accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await runAccessibilityAudit(page);
expect(results.violations).toHaveLength(0);
});bash
undefinedCLI tools
CLI tools
npx @axe-core/cli https://example.com
npx pa11y https://example.com
lighthouse https://example.com --only-categories=accessibility
undefinednpx @axe-core/cli https://example.com
npx pa11y https://example.com
lighthouse https://example.com --only-categories=accessibility
undefinedRemediation Patterns
修复模式
Fix: Missing Form Labels
修复方案:缺失表单标签
html
<!-- Before -->
<input type="email" placeholder="Email" />
<!-- After: Option 1 - Visible label -->
<label for="email">Email address</label>
<input id="email" type="email" />
<!-- After: Option 2 - aria-label -->
<input type="email" aria-label="Email address" />
<!-- After: Option 3 - aria-labelledby -->
<span id="email-label">Email</span>
<input type="email" aria-labelledby="email-label" />html
<!-- Before -->
<input type="email" placeholder="Email" />
<!-- After: Option 1 - Visible label -->
<label for="email">Email address</label>
<input id="email" type="email" />
<!-- After: Option 2 - aria-label -->
<input type="email" aria-label="Email address" />
<!-- After: Option 3 - aria-labelledby -->
<span id="email-label">Email</span>
<input type="email" aria-labelledby="email-label" />Fix: Insufficient Color Contrast
修复方案:颜色对比度不足
css
/* Before: 2.5:1 contrast */
.text {
color: #767676;
}
/* After: 4.5:1 contrast */
.text {
color: #595959;
}
/* Or add background */
.text {
color: #767676;
background: #000;
}css
/* Before: 2.5:1 contrast */
.text {
color: #767676;
}
/* After: 4.5:1 contrast */
.text {
color: #595959;
}
/* Or add background */
.text {
color: #767676;
background: #000;
}Fix: Keyboard Navigation
修复方案:键盘导航
javascript
// Make custom element keyboard accessible
class AccessibleDropdown extends HTMLElement {
connectedCallback() {
this.setAttribute("tabindex", "0");
this.setAttribute("role", "combobox");
this.setAttribute("aria-expanded", "false");
this.addEventListener("keydown", (e) => {
switch (e.key) {
case "Enter":
case " ":
this.toggle();
e.preventDefault();
break;
case "Escape":
this.close();
break;
case "ArrowDown":
this.focusNext();
e.preventDefault();
break;
case "ArrowUp":
this.focusPrevious();
e.preventDefault();
break;
}
});
}
}javascript
// Make custom element keyboard accessible
class AccessibleDropdown extends HTMLElement {
connectedCallback() {
this.setAttribute("tabindex", "0");
this.setAttribute("role", "combobox");
this.setAttribute("aria-expanded", "false");
this.addEventListener("keydown", (e) => {
switch (e.key) {
case "Enter":
case " ":
this.toggle();
e.preventDefault();
break;
case "Escape":
this.close();
break;
case "ArrowDown":
this.focusNext();
e.preventDefault();
break;
case "ArrowUp":
this.focusPrevious();
e.preventDefault();
break;
}
});
}
}Best Practices
最佳实践
Do's
建议事项
- Start early - Accessibility from design phase
- Test with real users - Disabled users provide best feedback
- Automate what you can - 30-50% issues detectable
- Use semantic HTML - Reduces ARIA needs
- Document patterns - Build accessible component library
- 尽早开始 - 从设计阶段就考虑无障碍
- 与真实用户测试 - 残障用户的反馈最有价值
- 尽可能自动化 - 30-50%的问题可通过自动化检测
- 使用语义化HTML - 减少对ARIA的依赖
- 记录模式 - 构建无障碍组件库
Don'ts
避免事项
- Don't rely only on automated testing - Manual testing required
- Don't use ARIA as first solution - Native HTML first
- Don't hide focus outlines - Keyboard users need them
- Don't disable zoom - Users need to resize
- Don't use color alone - Multiple indicators needed
- 不要仅依赖自动化测试 - 必须配合人工测试
- 不要优先使用ARIA - 优先使用原生HTML
- 不要隐藏焦点轮廓 - 键盘用户需要它们
- 不要禁用缩放 - 用户需要调整大小
- 不要单独使用颜色 - 需搭配其他标识