为什么Web无障碍很重要?
Web无障碍(Accessibility,简称A11y)确保所有用户,包括残障人士,都能平等地访问和使用Web内容。全球约有15亿人(约占世界人口的16%)存在某种形式的残障,无障碍设计不是可选项,而是Web开发的基本责任。
此外,许多国家和地区已将Web无障碍纳入法律法规。例如,欧盟的《欧洲无障碍法案》(EAA)要求到2025年6月,所有数字产品和服务必须满足无障碍标准。
Web无障碍的核心理念是"人人可用"(Universal Access)——Tim Berners-Lee,万维网之父
WCAG 2.1 四大原则(POUR)
WCAG(Web Content Accessibility Guidelines)是Web无障碍的国际标准,其核心围绕四大原则展开:
| 原则 | 英文 | 含义 | 关键要求 |
|---|---|---|---|
| 可感知 | Perceivable | 信息和界面组件必须以用户可感知的方式呈现 | 文本替代、字幕、可调整的内容呈现 |
| 可操作 | Operable | 界面组件和导航必须可操作 | 键盘可访问、足够的时间、无癫痫诱因 |
| 可理解 | Understandable | 信息和用户界面操作必须可理解 | 可读性、可预测性、输入辅助 |
| 健壮性 | Robust | 内容必须足够健壮,能被各种用户代理解析 | 兼容辅助技术、有效的HTML |
语义化HTML基础
使用正确的HTML元素是实现无障碍的第一步。语义化标签不仅让代码更易读,更重要的是为辅助技术提供必要的结构信息。
正确的文档结构
<!-- 正确的语义化结构 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>页面标题 - 网站名称</title>
</head>
<body>
<header>
<nav aria-label="主导航">
<ul>
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<article>
<h1>页面主标题</h1>
<section aria-labelledby="section-1">
<h2 id="section-1">第一节</h2>
<p>内容...</p>
</section>
</article>
</main>
<footer>
<p>© 2026 网站名称</p>
</footer>
</body>
</html>
避免的反模式
<!-- 不推荐:使用 div 模拟按钮 -->
<div class="btn" onclick="handleClick()">点击我</div>
<!-- 不推荐:空的链接 -->
<a href="/page"></a>
<!-- 推荐:使用语义化元素 -->
<button type="button" onclick="handleClick()">点击我</button>
<!-- 推荐:链接提供有意义的文本 -->
<a href="/page">查看详细内容</a>
ARIA 属性详解
ARIA(Accessible Rich Internet Applications)属性为动态内容和复杂UI组件提供额外的无障碍信息。但切记:ARIA的第一条规则是——如果能用原生HTML实现,就不要用ARIA。
常用ARIA角色
<!-- 标记为警告信息 -->
<div role="alert" aria-live="assertive">
提交成功!
</div>
<!-- 标记为加载状态 -->
<div role="status" aria-live="polite">
正在加载中...
</div>
<!-- 标签页组件 -->
<div role="tablist" aria-label="内容标签">
<button role="tab" aria-selected="true" aria-controls="panel-1">
标签一
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2">
标签二
</button>
</div>
<div role="tabpanel" id="panel-1">内容一</div>
<div role="tabpanel" id="panel-2" hidden>内容二</div>
常用ARIA属性速查
| 属性 | 用途 | 示例 |
|---|---|---|
aria-label |
为元素提供可读标签 | <button aria-label="关闭对话框">×</button> |
aria-labelledby |
引用其他元素作为标签 | <div aria-labelledby="title1"> |
aria-describedby |
引用元素提供补充描述 | <input aria-describedby="hint1"> |
aria-hidden |
对辅助技术隐藏元素 | <span aria-hidden="true"> decorative icon </span> |
aria-expanded |
指示展开/折叠状态 | <button aria-expanded="false">菜单</button> |
aria-required |
标记必填字段 | <input aria-required="true"> |
颜色对比度
颜色对比度是WCAG中的重要要求,确保视力低下或色盲用户能够清晰阅读文本内容。
对比度要求
| 级别 | 正文文本 | 大号文本(18px+粗体或24px+) | UI组件 |
|---|---|---|---|
| AA(最低要求) | 4.5:1 | 3:1 | 3:1 |
| AAA(推荐) | 7:1 | 4.5:1 | — |
/* 使用 CSS 变量确保足够的对比度 */
:root {
--text-primary: #1a1a2e; /* 对比度约 16:1 on white */
--text-secondary: #4a4a6a; /* 对比度约 7:1 on white */
--text-muted: #6b7280; /* 对比度约 4.6:1 on white (AA) */
--accent: #2563eb; /* 对比度约 4.5:1 on white */
}
/* 高对比度模式支持 */
@media (prefers-contrast: high) {
:root {
--text-primary: #000000;
--text-secondary: #1a1a1a;
--text-muted: #333333;
}
}
/* 暗色模式支持 */
@media (prefers-color-scheme: dark) {
:root {
--text-primary: #f0f0f0;
--text-secondary: #d0d0d0;
--text-muted: #a0a0a0;
}
}
键盘导航
许多用户依赖键盘而非鼠标进行网页导航。确保所有交互元素都能通过键盘访问是无障碍的基本要求。
键盘交互规范
- Tab — 在可聚焦元素间移动
- Shift+Tab — 反向移动焦点
- Enter / Space — 激活按钮或链接
- 方向键 — 在单选按钮组、标签页、下拉菜单中导航
- Escape — 关闭模态框、下拉菜单
焦点管理代码示例
/* 显示焦点指示器 */
:focus-visible {
outline: 3px solid var(--accent);
outline-offset: 2px;
border-radius: 4px;
}
/* 隐藏默认焦点(仅在键盘导航时显示) */
:focus:not(:focus-visible) {
outline: none;
}
/* 模态框的焦点陷阱 */
function trapFocus(modal) {
const focusable = modal.querySelectorAll(
'a[href], button:not([disabled]), input:not([disabled]), ' +
'select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
const firstEl = focusable[0];
const lastEl = focusable[focusable.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstEl) {
e.preventDefault();
lastEl.focus();
} else if (!e.shiftKey && document.activeElement === lastEl) {
e.preventDefault();
firstEl.focus();
}
}
if (e.key === 'Escape') {
closeModal(modal);
}
});
firstEl.focus();
}
表单无障碍
表单是Web无障碍中最关键的部分之一。正确的标签关联和错误提示对屏幕阅读器用户至关重要。
<!-- 正确的表单无障碍实践 -->
<form>
<div class="form-group">
<label for="username">
用户名 <span aria-hidden="true">*</span>
<span class="sr-only">(必填)</span>
</label>
<input
type="text"
id="username"
name="username"
aria-required="true"
aria-invalid="false"
aria-describedby="username-hint"
/>
<span id="username-hint" class="hint">
请输入4-20个字符的用户名
</span>
</div>
<div class="form-group">
<label for="email">邮箱地址</label>
<input
type="email"
id="email"
name="email"
aria-required="true"
aria-invalid="true"
aria-describedby="email-error"
/>
<span id="email-error" class="error" role="alert">
请输入有效的邮箱地址
</span>
</div>
<button type="submit">提交</button>
</form>
<!-- 无障碍的跳转链接(仅在聚焦时显示) -->
<style>
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.skip-link {
position: absolute;
top: -40px;
left: 0;
padding: 8px 16px;
background: var(--accent);
color: #fff;
z-index: 100;
transition: top 0.3s;
}
.skip-link:focus {
top: 0;
}
</style>
<a href="#main-content" class="skip-link">跳转到主要内容</a>
图像无障碍
为图像提供恰当的替代文本是图片无障碍的核心要求。
- 信息性图片:使用
alt描述图片内容和含义 - 装饰性图片:使用空
alt=""或 CSS 背景图 - 功能性图片(如图标按钮):alt 应描述操作而非外观
- 复杂图表:使用
<figure>+<figcaption>或长描述
<!-- 信息性图片 -->
<img src="chart.png" alt="2025年销售趋势图,Q3达到峰值120万元">
<!-- 装饰性图片 -->
<img src="decorative-border.png" alt="" role="presentation">
<!-- 图标按钮 -->
<button aria-label="搜索">
<svg aria-hidden="true">
<use href="#icon-search"></use>
</svg>
</button>
<!-- 复杂图表 -->
<figure>
<img src="complex-chart.png" alt="年度用户增长数据图表">
<figcaption>
图1:2024-2025年月度活跃用户增长趋势。
完整数据见<a href="/data/active-users.csv">CSV文件</a>。
</figcaption>
</figure>
无障碍测试工具
自动化工具可以检测约30-40%的无障碍问题,但人工测试仍然不可替代。
| 工具 | 类型 | 特点 |
|---|---|---|
| axe DevTools | 浏览器扩展 / API | 业界标准,集成于Chrome/Firefox,检测准确率高 |
| Lighthouse | Chrome内置 | 综合审计,包含无障碍评分 |
| NVDA | 屏幕阅读器 | Windows免费开源,真实的屏幕阅读器体验 |
| VoiceOver | 屏幕阅读器 | macOS/iOS内置,Safari配合效果最佳 |
| WAVE | 在线工具 | 可视化标注问题,适合初学者 |
| pa11y | 命令行/CI | 自动化测试,集成到持续集成流程 |
无障碍检查清单
- 所有图片都有适当的 alt 文本
- 页面有正确的标题层级(h1 → h2 → h3)
- 所有表单元素都有关联的 label
- 颜色对比度满足 WCAG AA 标准
- 所有功能都可以通过键盘操作
- 焦点顺序符合逻辑
- 焦点指示器清晰可见
- 页面有跳过导航的链接
- 使用 ARIA 属性增强复杂组件的无障碍性
- 动态内容更新通过 aria-live 通知屏幕阅读器
- HTML 通过 W3C 验证
- 使用 axe 或 Lighthouse 进行自动化测试