可访问性也是工程
很多人把可访问性当成「给残障人士的补丁」:功能做完了,才想起来要加几个 aria 属性、调一调对比度。但在真实产品里,可访问性的受益者远比想象中多——色弱的人看不清低对比度文字,手部不便的人只能用键盘操作,视力下降的老年人需要放大字号,这些都不是小众场景。
把可访问性当工程来做,意味着它不再是上线前的补救,而是从结构、样式、交互到测试的一整套约束。它和性能、安全一样,属于产品的基本质量属性:不达标,功能再全也不算完成。
可访问性不是少数人的需求,而是产品的基本质量属性。
- 误解可访问性只是加几个 aria 属性。
- 误解没有视障用户,所以不需要做。
- 误解自动化工具扫一遍就达标了。
- 正解结构、样式、交互、测试缺一不可。
无障碍的四个原则:POUR
做无障碍先记住四个字母:POUR。任何内容要能被无障碍访问,必须满足可感知、可操作、可理解、健壮四个原则,这也是 WCAG 的四大支柱。
| 原则 | 含义 | 常见检查点 |
|---|---|---|
| 可感知 | 信息能用某种感官获取 | 图片有替代文本、视频有字幕 |
| 可操作 | 界面能用键盘等操作 | 所有功能可键盘到达、可操作 |
| 可理解 | 信息与操作能被看懂 | 文案清楚、导航一致、错误可说明 |
| 健壮 | 能被辅助技术可靠解析 | 语义正确、标准合规、兼容性好 |
这四个原则是检查清单的起点:任何一个功能,都可以问一句「它满足 POUR 吗」。回答不出来,说明这块还没做到位。
语义化 HTML:让结构自带含义
屏幕阅读器读网页,靠的不是视觉,而是代码里的语义。一个用 div 堆出来的按钮,和一个真正的 button 元素,对辅助技术来说完全是两回事。所以第一原则是:能用原生元素,就不要自造。
// 差的写法:div 冒充按钮
<div class="btn" onclick="submit()">提交</div>
// 好的写法:原生 button
<button type="submit">提交</button>
// 语义化标题与列表
<h1>订单管理</h1>
<ul>
<li>待付款</li>
<li>待发货</li>
</ul>
只有原生元素确实表达不了时,才用 ARIA 补足:例如自定义的折叠面板、弹窗、标签页。ARIA 的作用是给没有语义的自定义组件补语义,而不是给原生元素加戏。
- 规则优先用原生元素,ARIA 是补充不是替代。
- 规则能不用就不用:多余的 aria 比没有更糟。
- 规则role、状态、标签要配套完整。
键盘导航与焦点管理
键盘是很多辅助技术的共同底座:屏幕阅读器、语音控制,底层都是键盘事件。所以「键盘能不能到达」是可操作原则的核心。
- Tab 顺序要符合阅读顺序,用 tabindex="0" 让自定义控件可聚焦,用 -1 让脚本可聚焦但不在 Tab 序列。
- 焦点要有可见指示:默认的 outline 不要随意去掉,去掉就要自己画一个等价的焦点环。
- 弹窗打开时焦点要移入,关闭时焦点要还回触发它的元素;页面滚动时不能让焦点掉到屏幕外。
- 每个交互都要支持对应的键盘操作:按钮用回车或空格,下拉框要能上下选。
// 焦点管理示例:弹窗开关
function openDialog(dlg, trigger) {
dlg.hidden = false;
dlg.focus(); // 焦点移入弹窗
}
function closeDialog(dlg, trigger) {
dlg.hidden = true;
trigger.focus(); // 焦点还给触发元素
}
// 永远保留可见焦点环
:focus-visible {
outline: 2px solid #1E5FA8;
outline-offset: 2px;
}
有一个简单到几乎免费的检查:关掉鼠标,只用键盘把核心流程走一遍。走不通的地方,就是可访问性欠债的地方。
颜色、对比度与文字
颜色是信息的重要载体,但不能是唯一载体。用颜色区分状态时,要同时给形状、文字或图标做补充:比如错误提示不仅变红,还要带一个图标和文字说明。
| 场景 | 对比度要求 | 对应级别 |
|---|---|---|
| 正文文字 | 4.5 : 1 以上 | AA |
| 大号文字(18 号以上) | 3 : 1 以上 | AA |
| 图形与图标 | 3 : 1 以上 | AA |
| 更高标准 | 7 : 1 以上 | AAA |
检查对比度可以直接用工具算:把前景色和背景色丢进去,看比率是否达标。日常写样式时养成习惯——浅色文字配深色背景、深色文字配浅色背景,避免「灰字配灰底」这种看着高级但读不清的组合。
文字方面,还要允许用户放大:不要用固定像素锁死字号,优先用相对单位;文案不要写死在一张图里,让文字真的还是文字。
自动化检测与人工测试
自动化扫描工具能查出大约三到四成的可访问性问题:缺 alt、对比度不足、按钮没有可访问名称、表单标签缺失。所以自动化检测是低成本的第一道防线,但绝不是全部。
// 流水线里的自动化检查示例(示意)
// CI 中对每个页面跑 axe 扫描,发现问题即失败
const results = await axe.run(page, {
runOnly: { type: "tag", values: ["wcag2aa"] }
});
if (results.violations.length > 0) {
console.error(results.violations);
process.exit(1); // 门禁:有违规就拦截
}
剩下六成靠人工:真实用屏幕阅读器走一遍、只用键盘走一遍、放大到两倍看布局是否崩、模拟色弱视角看是否还能分辨。把这些场景写进验收标准,而不是靠「记得测一下」。
把无障碍做进开发流程
可访问性做不进去,通常不是因为不想做,而是因为没有位置。要让它成为默认,需要把检查点放到流程的固定位置:
- 设计评审时带上对比度和焦点态的设计稿。
- 开发自测清单里加上键盘走查和 alt 检查。
- Code Review 时把 a11y 问题列为阻塞项。
- CI 里跑自动化扫描,违规即拦截。
- 发布前用屏幕阅读器做一轮冒烟。
可访问性欠债和性能欠债一样,越晚还越贵。
当这些检查成为流程的一部分,可访问性就不再是某个人的责任,而是团队默认的工程质量。产品对所有人可用,也从一句口号变成了可验收的事实。