无障碍化 Accessibility
什么是 Accessibility?
- 以任何方式访问网络的用户(移动端、电视、手表…),无论听觉、视觉、身体和认知能力如何(视障、听障、运动功能障碍…),应用程序都是可以理解和使用的
- 网站不应该造成伤害(诱发光敏性癫痫等)
可以从什么方面作出努力?
HTML
语义化结构
<button> vs <div>
提供了默认样式、提供了键盘的无障碍(tab 键更换按钮、enter 键点击按钮)
<h1> <h2> <p> vs <font> <br> <hr> <i>
便于屏幕阅读器识别标题和段落结构 🆚 没有任何可定位的标记的一大坨
- 替代文本
alt=""
属性,包含对图像的描述,向无法看到/听到某些内容的用户传达其含义和内容。如果 alt 为空,表示该图像只用于装饰(或role =“presentation”
阻止辅助设备读出替代文本)title
属性,屏幕阅读器也会读出 title 的内容<track>
元素向视频/音频添加文本轨道
- 提供元素之间的联系和上下文,例如
<label for=""><input>
WAI-ARIA 属性
当原生 HTML 元素无法满足需求时,考虑 ARIA(Accessible Rich Internet Applications)属性,帮助解读网页结构和交互方式
- aria-hidden:表示是否对辅助技术隐藏该元素
- role:制定元素的角色
- aria-labelledby:父节点设置,会链接到对应 id 的元素,方便把分散在多个 DOM,逻辑上属于一个整体的内容打包阅读
CSS
要确保无 css 的情况下,内容可读,顺序有意义
颜色及对比度
WebAIM 的 Color Contrast Checker 之类的工具来检查方案是否有足够对比度
隐藏的内容
position: absolute
好于 visibility: hidden; display: none;
,前者不阻止屏幕阅读器读取被隐藏的内容
JavaScript
结构交给 HTML,尽量不使用 JS 配合 <div>
伪造功能(unobtrusive 原则)
焦点管理
相比较<button><a>
这样自带语义的元素,<div>
不能用.foucs()
,需要配合tabindex="-1"
属性,和.pop:focus-visible {outline: 0}
- 场景是现在很常见的单页面里,进行路由切换/ajax 更改内容时,进行焦点重置,让辅助阅读设备重头开始读,方便视障人士
<nav>
<a href="/">Home</a>
<a href="/goods">goods</a>
<a href="/user">user</a>
</nav>
<main>
+ // tabindex="-1",元素可聚焦,不可通过键盘导航访问
+ <h2 tabindex="-1">商城</h2>
<Link />
</main>
+ <script>
+ function routerChange() {
+ const heading = document.querySelector('h2')
+ heading.focus()
+ document.title = heading.textContent
+ }
+ </script>
- Dialog 配合 A11y
需求:弹窗打开时聚焦于弹窗上,限制对页面其他元素的访问,退出弹窗时焦点退回到之前的位置
给弹窗增加 aria 属性
<section
id="alert-dialog"
role="dialog"
aria-modal="true"
aria-label="home-dialog"
tanindex="-1"
>
<h2>TITLE</h2>
...
<button></button>
</section>
转移焦点
function showSelfAlert() {
// 获取目标元素
var mask = document.querySelector('.mask');
// 显示弹窗
mask.style.display = 'block';
// 等待DOM更新,在下一个事件循环时
setTimeout(function() {
// 设置焦点到遮罩层或弹窗的元素上
var dialog = document.getElementById('aria-mask-dialog');
if(dialog) {
dialog.focus();
}
}, 0);
}
<section aria-live="polite"></section>
// aria-live 默认属性为off,
// polite 在系统空闲时朗读
// assertive 立刻阅读
限制焦点
- 使用 event capturing 监听 focus 事件,处理阶段:捕获-目标-冒泡
document.addEventListener('focus', function(event){
const dialog = document.getElementById('dialog');
if(dialogOpen && !dialog.contains(event.target)){
event.stopPropagation();
dialog.focus();
}
})
打开弹窗前记录最后一个焦点元素,结束后把焦点挂回去
// 获取当前聚焦的元素
let lastFouceElement = document.activeElement;
// close dialog
lastFouceElement.focus()
参考&致谢
https://developer.mozilla.org/zh-CN/docs/Learn/Accessibility