3.8.1 WCAG 标准
一句话破题
WCAG 是可访问性的"交规",遵守它,你的网站就能让更多人使用。
核心价值
WCAG (Web Content Accessibility Guidelines) 是 W3C 制定的可访问性标准。满足 WCAG 2.1 AA 级是大多数法规要求的最低标准。
WCAG 四大原则
| 原则 | 含义 | 关键要求 |
|---|---|---|
| 可感知 | 用户能感知到内容 | 图片有替代文本、视频有字幕 |
| 可操作 | 用户能操作界面 | 键盘可访问、有足够时间 |
| 可理解 | 用户能理解内容 | 语言清晰、行为可预测 |
| 健壮性 | 兼容辅助技术 | 语义化 HTML、ARIA 属性 |
键盘可访问性
核心要求:所有功能必须能通过键盘操作。
tsx
// 差:div 做按钮,无法键盘访问
<div onClick={handleClick}>点击我</div>
// 好:使用原生 button
<button onClick={handleClick}>点击我</button>
// 如果必须用 div,添加必要属性
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick()
}
}}
>
点击我
</div>焦点管理:
tsx
// 焦点可见
.focus-visible:focus {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
// 跳过导航链接
<a href="#main" className="sr-only focus:not-sr-only">
跳转到主要内容
</a>
<main id="main">...</main>语义化 HTML
tsx
// 差:div 嵌套一切
<div class="nav">
<div class="nav-item">首页</div>
</div>
<div class="main">
<div class="title">文章标题</div>
</div>
// 好:语义化标签
<nav>
<a href="/">首页</a>
</nav>
<main>
<h1>文章标题</h1>
<article>...</article>
</main>ARIA 属性
当语义化 HTML 不够时,使用 ARIA:
tsx
// 模态框
<div
role="dialog"
aria-labelledby="dialog-title"
aria-describedby="dialog-description"
aria-modal="true"
>
<h2 id="dialog-title">确认删除</h2>
<p id="dialog-description">删除后无法恢复,确定吗?</p>
<button>确定</button>
<button>取消</button>
</div>
// 加载状态
<button aria-busy={isLoading} disabled={isLoading}>
{isLoading ? '保存中...' : '保存'}
</button>
// 展开/收起
<button
aria-expanded={isOpen}
aria-controls="menu-content"
>
菜单
</button>
<div id="menu-content" hidden={!isOpen}>
...
</div>常用 ARIA 属性
| 属性 | 用途 | 示例 |
|---|---|---|
aria-label | 为元素提供标签 | <button aria-label="关闭">X</button> |
aria-labelledby | 引用另一元素作为标签 | aria-labelledby="title" |
aria-describedby | 引用描述性文本 | aria-describedby="help-text" |
aria-hidden | 对辅助技术隐藏 | <div aria-hidden="true">装饰性内容</div> |
aria-live | 动态内容区域 | <div aria-live="polite"> |
role | 定义元素角色 | role="button" |
图片替代文本
tsx
// 信息性图片:描述内容
<img
src="/chart.png"
alt="2024年销售额增长趋势图,Q1到Q4分别为100万、150万、200万、280万"
/>
// 装饰性图片:空 alt
<img src="/decorative-line.png" alt="" />
// 功能性图片:描述功能
<button>
<img src="/search-icon.svg" alt="搜索" />
</button>表单可访问性
tsx
// 关联 label 和 input
<div>
<label htmlFor="email">邮箱地址</label>
<input
id="email"
type="email"
aria-describedby="email-help"
aria-invalid={!!errors.email}
/>
<p id="email-help">我们不会分享你的邮箱</p>
{errors.email && (
<p role="alert" className="text-red-500">
{errors.email}
</p>
)}
</div>
// 必填字段
<label>
邮箱 <span aria-hidden="true">*</span>
<span className="sr-only">(必填)</span>
</label>
<input required aria-required="true" />屏幕阅读器隐藏类
css
/* 视觉隐藏但屏幕阅读器可读 */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* 聚焦时显示 */
.sr-only.focus:focus {
position: static;
width: auto;
height: auto;
padding: inherit;
margin: inherit;
overflow: visible;
clip: auto;
white-space: normal;
}测试工具
| 工具 | 用途 |
|---|---|
| axe DevTools | Chrome 扩展,自动检测问题 |
| Lighthouse | Chrome 内置,审计报告 |
| WAVE | 在线检测工具 |
| VoiceOver | macOS 内置屏幕阅读器 |
| NVDA | Windows 免费屏幕阅读器 |
tsx
// 使用 eslint-plugin-jsx-a11y 自动检测
// .eslintrc.js
module.exports = {
extends: ['plugin:jsx-a11y/recommended'],
}AI 协作指南
核心意图:让 AI 帮你检查和修复可访问性问题。
需求定义公式:
- 检查范围:[组件/页面] 的可访问性
- 标准级别:WCAG 2.1 [A/AA/AAA]
- 关注点:[键盘/屏幕阅读器/颜色对比度]
示例 Prompt:
请检查这个模态框组件的可访问性:
1. 确保键盘可以打开、关闭、在内部导航
2. 添加正确的 ARIA 属性
3. 打开时焦点移入,关闭时焦点返回触发元素
4. ESC 键可关闭验收清单
- [ ] 所有功能可通过键盘操作
- [ ] 焦点状态清晰可见
- [ ] 图片有合适的替代文本
- [ ] 表单有关联的标签
- [ ] 使用语义化 HTML
- [ ] 通过 axe/Lighthouse 检测
