Web 应该为所有人服务
全球有超过 10 亿人患有某种形式的残疾。视力障碍、听力障碍、运动障碍、认知障碍——这些用户同样需要访问 Web 内容和服务。无障碍访问(Accessibility,简称 a11y)不是锦上添花,而是必要条件。
W3C 的 Web Accessibility Initiative(WAI)制定了一系列标准,帮助开发者构建可访问的 Web 内容。其中最重要的是 WCAG(Web Content Accessibility Guidelines)。
WCAG 四大原则
WCAG 2.1 定义了四个基本原则,每个原则都有具体的成功标准:
可感知
信息和 UI 组件必须能被用户感知
- 文本替代
- 时间媒体替代
- 可适应
- 可区分
可操作
UI 组件和导航必须可操作
- 键盘可访问
- 足够的时间
- 不引起癫痫
- 可导航
可理解
信息和 UI 操作必须可理解
- 可读
- 可预测
- 输入协助
健壮性
内容必须足够健壮,能被各种用户代理可靠地解释
- 兼容性
语义化 HTML
使用正确的 HTML 标签是无障碍访问的基础:
<!-- 正确:使用语义化标签 -->
<header>
<nav aria-label="主导航">
<ul>
<li><a href="/">首页</a></li>
<li><a href="/docs">文档</a></li>
<li><a href="/blog">博客</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>文章标题</h1>
<p>文章内容...</p>
</article>
<aside aria-label="相关链接">
<h2>相关资源</h2>
<ul>
<li><a href="#">链接1</a></li>
<li><a href="#">链接2</a></li>
</ul>
</aside>
</main>
<footer>
<p>© 2024 W3C 标准</p>
</footer>
<!-- 错误:全部使用 div -->
<div class="header">...</div>
<div class="content">...</div>
<div class="sidebar">...</div>
<div class="footer">...</div>
ARIA 属性
当 HTML 语义不足以表达元素用途时,使用 ARIA 属性:
<!-- 标识区域 -->
<div role="navigation" aria-label="主导航">...</div>
<div role="search" aria-label="搜索">...</div>
<div role="dialog" aria-modal="true">...</div>
<!-- 描述状态 -->
<button aria-pressed="true">已选择</button>
<button aria-expanded="false">展开菜单</button>
<div aria-live="polite" aria-atomic="true">
消息已发送
</div>
<!-- 表单标签 -->
<label for="email">邮箱地址</label>
<input type="email"
id="email"
aria-required="true"
aria-invalid="false">
<!-- 关联错误信息 -->
<input type="text"
id="username"
aria-describedby="username-error">
<span id="username-error"
role="alert"
class="error">
用户名长度至少 3 个字符
</span>
键盘导航
确保所有交互都可以通过键盘完成:
<!-- 可聚焦的元素 -->
<button onclick="doSomething()">
点击按钮
</button>
<a href="/page" role="button">
链接样式的按钮
</a>
<div role="button"
tabindex="0"
onkeydown="handleKey(event)"
onclick="doSomething()">
自定义按钮
</div>
<script>
function handleKey(event) {
if (event.key === 'Enter' || event.key === ' ') {
doSomething();
event.preventDefault();
}
}
</script>
/* 清晰的焦点样式 */
button:focus,
a:focus,
input:focus,
[tabindex]:focus {
outline: 3px solid #3B82F6;
outline-offset: 2px;
}
/* 跳过导航链接 */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #3B82F6;
color: white;
padding: 8px;
text-decoration: none;
}
.skip-link:focus {
top: 0;
}
图片替代文本
为所有有意义的图片提供替代文本:
<!-- 有意义的图片 -->
<img src="chart.png"
alt="2024 年销售额增长了 35%"
width="500"
height="300">
<!-- 装饰性图片 -->
<img src="decorative.png"
alt=""
role="presentation">
<!-- 复杂图片需要详细描述 -->
<img src="complex-chart.png"
alt="图表显示:1月增长10%,2月增长15%,3月增长20%"
longdesc="#chart-description">
<div id="chart-description" class="sr-only">
详细图表描述...
</div>
<!-- 使用 figure 和 figcaption -->
<figure>
<img src="diagram.png"
alt="流程图展示用户注册流程">
<figcaption>
图 1: 用户注册流程图
</figcaption>
</figure>
颜色和对比度
确保颜色对比度足够,信息不依赖颜色:
/* WCAG AA 级别:对比度至少 4.5:1 */
.text {
color: #333; /* 背景白色 */
background: #fff;
}
/* 更好的对比度 */
.text {
color: #1a1a1a;
background: #ffffff;
}
/* 大文本(18pt+)对比度至少 3:1 */
h1 {
color: #333; /* 24px 字体 */
}
/* 不依赖颜色传递信息 */
.error {
color: #dc2626;
font-weight: bold;
border-left: 4px solid #dc2626;
}
.success {
color: #16a34a;
font-weight: bold;
border-left: 4px solid #16a34a;
}
/* 支持高对比度模式 */
@media (prefers-contrast: high) {
.button {
background: #000;
color: #fff;
border: 2px solid #fff;
}
}
表单无障碍
让表单易于填写和理解:
<form aria-label="注册表单">
<!-- 清晰的标签 -->
<label for="username">
用户名
<span class="required" aria-hidden="true">*</span>
</label>
<input type="text"
id="username"
name="username"
required
aria-required="true"
aria-describedby="username-help">
<small id="username-help">3-20 个字符</small>
<!-- 使用 fieldset 组织相关元素 -->
<fieldset>
<legend>性别</legend>
<label>
<input type="radio"
name="gender"
value="male">
男
</label>
<label>
<input type="radio"
name="gender"
value="female">
女
</label>
</fieldset>
<!-- 提交按钮 -->
<button type="submit">注册</button>
</form>
减少动画
尊重用户的偏好设置:
/* 检测用户是否偏好减少动画 */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* 平滑滚动 */
html {
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
}
测试无障碍
使用工具和真实用户测试无障碍访问:
键盘测试
使用 Tab 键导航,确保所有元素可访问
屏幕阅读器
使用 NVDA、JAWS 或 VoiceOver 测试
自动化工具
使用 axe DevTools、Lighthouse 检测问题
用户测试
邀请残疾用户进行真实测试
使用对比度检查工具验证颜色
WCAG 验证
使用 WAI-ARIA Authoring Practices 验证
总结
无障碍访问是 Web 开发的重要组成部分。通过遵循 WCAG 标准、使用语义化 HTML、添加 ARIA 属性、确保键盘导航,我们可以让 Web 真正为所有人服务。
记住,无障碍访问不仅是道德责任,也是法律要求。许多国家和地区都有相关法律要求网站满足无障碍标准。更重要的是,无障碍访问通常能改善所有用户体验——不仅是有障碍的用户。
让 Web 成为一个包容、开放、人人可访问的数字空间,这是我们每个开发者的责任。