什么是 Web 无障碍
无障碍(Accessibility,简称 a11y)指让网站对尽可能多的人可用:视力障碍者靠读屏软件听页面,行动障碍者靠键盘或辅助设备操作,色弱用户靠对比度区分信息,还有暂时性的场景——阳光刺眼、一只手抱娃、网速慢。无障碍不是「照顾少数人」的特殊功能,而是产品可用性的底线。
行业标准是 W3C 的 WCAG(Web Content Accessibility Guidelines),按 A、AA、AAA 三级划分要求,绝大多数产品以 AA 为目标。它围绕四条原则组织:可感知、可操作、可理解、健壮。前端做无障碍不是「写完再补」,而是在结构、交互、视觉三个层面从设计时就纳入约束。
<img src="hero.png" alt="春季新品发布主视觉">
<button type="button">提交订单</button>
上面两行是「无障碍默认正确」的写法:图片有替代文本,按钮用原生元素自带键盘与语义。多数无障碍问题恰恰来自反着做——用 `div` 模拟按钮、图片不给 alt、颜色当唯一信号。
无障碍不是功能,是「基本可用」本身。做得对时,所有人都是受益者。
- WCAG四大原则与 AA 标准。
- 语义化HTML 与 ARIA。
- 键盘导航与焦点管理。
- axe自动化检测。
语义化 HTML 是无障碍的地基
读屏软件和搜索引擎一样,靠 HTML 语义理解页面。`header`、`nav`、`main`、`article`、`aside`、`footer` 这些 landmark 让辅助技术可以快速跳转;`h1` 到 `h6` 的层级是页面的「目录」;`ul` 表示列表、`table` 表示表格。用对元素,无障碍一半就完成了。
<nav aria-label="主导航">
<a href="#overview">概览</a>
<a href="#guide">指南</a>
</nav>
<button type="button">立即下载</button>
<!-- 不要用 div + onclick 模拟按钮 -->
反过来,滥用 `div` 和 `span` 会抹掉所有语义,读屏用户听到的只是一串无结构的文本。经验法则:能用原生元素就不用自定义组件;`a` 用于跳转、`button` 用于动作,两者不要互换。
ARIA 角色与属性
原生元素表达不了的复杂控件,用 ARIA 补齐语义。`aria-label` 给无文本的图标按钮补名字;`aria-live` 让动态更新的区域被读屏实时播报;`aria-expanded` 表明折叠面板状态;`role` 声明组件的语义角色。
<button class="icon-btn" aria-label="关闭弹窗">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l9 5v8l-9 5-9-5V8z" fill="currentColor"/></svg>
</button>
<div role="alert" aria-live="assertive">保存失败,请重试</div>
ARIA 的第一条规则是「能不用就不用」:优先原生语义,ARIA 只做补充。第二条是「写了就要维护」:`aria-expanded`、`aria-checked` 这类状态必须在交互后同步更新,状态失真比没有更糟。第三条,`aria-hidden="true"` 只用于纯装饰内容,绝不能用在可聚焦元素上。
键盘导航与焦点管理
键盘是很多用户的唯一输入方式。基本要求:所有可交互元素可用 Tab 到达、Enter 或空格触发;焦点环(focus ring)清晰可见;弹窗打开时焦点移入、关闭后归还;长页面提供「跳到主要内容」的跳过链接。
<a class="skip-link" href="#main">跳到主要内容</a>
// 弹窗关闭后归还焦点
function closeDialog() {
dialog.hidden = true;
triggerBtn.focus();
}
`tabindex` 要克制:`-1` 让元素可编程聚焦(配合脚本移动焦点)、但不进 Tab 顺序;`0` 表示可 Tab;大于 `0` 的正值会打乱自然顺序,应尽量避免。焦点管理是「程序员的秩序感」:每一次交互后,焦点落在哪里,都要有意识决定。
表单无障碍
表单是障碍重灾区:没有 label 的输入框读屏只能念「编辑框」;校验错误只靠红框,色盲用户无从分辨。正确做法是每个输入都有关联的 `label`,错误信息用文本 + `aria-describedby` 关联到字段,必填标记用文字而不是只用星号。
<label for="email">邮箱地址</label>
<input id="email" type="email" required
aria-describedby="email-err">
<p id="email-err" role="alert">请输入正确的邮箱格式</p>
相关选项用 `fieldset` 和 `legend` 分组,读屏会先念组名再念选项。错误提示不仅要有颜色变化,还要有文字说明;提交后把焦点移到第一条错误上,用户不用从头摸索。
色彩对比度与动效偏好
WCAG AA 要求正文对比度至少 4.5:1,大号文字 3:1。对比度不足的典型是浅灰文字配白底——在设计稿里「高级」,在真实屏幕上「看不见」。颜色也不能当唯一信息通道:错误、成功、状态的区分都要配图标或文字。
@media (prefers-reduced-motion: reduce) {
* { animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important; }
}
动效也要尊重用户偏好:`prefers-reduced-motion` 媒体查询识别「减少动态效果」的系统设置,前庭障碍用户对大幅晃动会恶心头晕。尊重它,不是砍掉所有动画,而是把装饰性动画关掉、保留必要的信息反馈。
无障碍测试与自动化
- 接入 axe-core:构建或 CI 阶段自动扫描页面,能拦下大部分缺失 alt、label 等规则类问题。
- Lighthouse 无障碍评分:每轮发布前跑一次,看 AXE 违规清单。
- 键盘走查:从 Tab 键开始,纯键盘完成一次核心业务流,检查焦点环与顺序。
- 读屏抽查:用 NVDA 或 VoiceOver 实际听一遍首页与表单页。
- 对比度工具:用 axe 或浏览器 DevTools 的对比度检查器过一遍正文与按钮。
- 把无障碍写进验收标准:无 alt、无 label、焦点丢失都算缺陷。
无障碍测试不该是发布前的临时抽检,而是每次迭代的常规回归项。