无障碍化 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