最近在看 AOM(Accessibility Object Model) 相关的草案,草案推出一两年了,发现还没有相关的中文文档或者博客谈到这个,看来国内做的人还是太少了,一般也只有大厂会去跟进这一块。下面我就介绍 AOM 相关的特性,内容主要翻译自草案,也会加上自己的一些理解,同时复现草案中的一些 Demo。
名词释义:下文中的无障碍指 Accessibility,可访问性指 Accessiable。
什么是 AOM
AOM(Accessibility Object Model),直译过来就是无障碍对象模型。AOM 提供了一系列的 JavaScript API,允许开发人员修改 HTML 页面的可访问性树(Accessibility Tree),换句话说:它允许开发者直接访问可访问性树。
这是什么意思呢?举个简单的例子,如果需要为一个 <div>
添加一个 role="button"
的属性,以往的做法是使用 setAttribute 设置相关属性:
el.setAttribute("role", "button")
而有了 AOM,我们可以更加直接地设置它的 role 属性:
el.role = "button"
上面两种写法的渲染出来的 DOM 结构是相同的:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NQj8QpdR-1596977616340)(https://imgkr2.cn-bj.ufileos.com/8c82e5b9-f0f7-42a7-9553-1583fdafdbb6.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=R1SL4qakZzob3smWGSQvSyzBalM%253D&Expires=1597062901)]
也就是说,除了现有的 DOM 方法(如setAttribute和getAttribute)之外,可访问性的相关属性有了自己的API,这些 API 设置 并计算成可访问性树的属性值。有了对可访问性信息的直接访问,我们可以在不做标记,也就是不设置标签属性的情况下,设置可访问性属性。另外,也可以为DOM中不存在的东西(比如画布元素的内容)创建可访问性树,测试可访问性可能会得到改善。
这张图很好的解释了 AOM 的渲染过程,DOM 树被翻译成页面的主要视觉和可访问性树,而可访问性树又可以通过一个或多个平台特定的可访问性 API 来访问。
浏览器启用 AOM
Chorme
在地址栏输入 chrome://flags
,然后启用 enable-experimental-web-platform-features
。
Safari
Develop > Experimental Features > Accessibility Object Model
Firefox
about:config accessibility.AOM.enabled = true
AOM 特性
AOM 目前是由 Mozilla、Google 和苹果公司的人员共同提出的,下面先总结一下它的特点。
简化属性
当我们为一些普通的控件添加无障碍功能时,可能需要维护大量的属性。即使是一个简单的禁用按钮,就可能需要使用到 role
、aria-label
以及 aria-disabled
等属性。如果状态多了,可能还需要添加更多的属性,这些属性通常需要手动添加,如果属性多的话会变得难以维护。
为了解决这个问题,AOM将允许开发者直接在 JavaScript 中设置元素的可访问性属性。例如,如果要对一个元素设置 aria-expanded,你可以直接在该元素上进行设置。
el.ariaExpanded = true;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCaOWpNe-1596977616345)(https://imgkr2.cn-bj.ufileos.com/96a19c44-61a4-4888-996e-ed8c6235f177.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=YB0dirDUj6VGJO1ycDUch6h55L4%253D&Expires=1597062976)]
而在以前,我们需要通过切换标记中的属性值来设置属性。
el.setAttribute("aria-expanded", true)
在 AOM 中,ARIA 属性集将作为 DOM 的属性存在,在 ARIA 1.2 规范中可以找到其 IDL 定义。
当然, 在使用 React 或者 Vue 在内的一些具有虚拟 DOM 的框架时,框架会建议不要直接修改 DOM,让框架来处理 DOM 的变化。在这种应用中,你可以仍在标签中定义相关的无障碍语义属性。针对这种情况,草案也提出了 ElementInternals
。
ElementInternals
对于自定义组件来说,草案建议开发者通过 ElementInternals 对象提供默认语义。开发者可以使用 ElementInternals 对象来修改自定义