AOM(Accessibility Object Model 无障碍对象模型)草案解读
最近在看 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 对象来修改自定义元素实例的语义状态,来响应用户交互。
目前,定义组件的无障碍能力时依然需要设置一大堆的属性,上面说到,这样会非常的难以维护。
<custom-tablist><custom-tab selected>Tab 1</custom-tab><custom-tab>Tab 2</custom-tab><custom-tab>Tab 3</custom-tab>
</custom-tablist><!-- 自定义元素 -->
<custom-tablist role="tablist"><custom-tabselectedrole="tab"aria-selected="true"aria-controls="tabpanel-1">Tab 1</custom-tab><custom-tab role="tab" aria-controls="tabpanel-2">Tab 2</custom-tab><custom-tab role="tab" aria-controls="tabpanel-3">Tab 3</custom-tab>
</custom-tablist>
使用 ElementInternals 设置默认语义,自定义元素可以避免去维护一大堆的属性,也可以避免元素在开发者删除 ARIA 属性时失去语义,元素看起来也更加简洁。
class CustomTab extends HTMLElement {constructor() {super();this._internals = customElements.createInternals(this);this._internals.role = "tab";}// 监听 'active' 属性static get observedAttributes() {return ["active"];}connectedCallback() {this._tablist = this.parentElement;}setTabPanel(tabpanel) {if (tabpanel.localName !== "custom-tabpanel" || tabPanel.id === "") return; // fail silentlythis._tabpanel = tabpanel;tabpanel.setTab(this);this._internals.ariaControls = tabPanel; // does not reflect}// ... setters/getters for custom properties which reflect to attributesattributeChangedCallback(name, oldValue, newValue) {switch (name) {case "active":let active = newValue != null;this._tabpanel.shown = active;// When the custom "active" attribute changes,// keep the accessible "selected" state in sync.this._internals.ariaSelected = newValue !== null;if (selected) this._tablist.setSelectedTab(this); // ensure no other tab has "active" setbreak;}}
}customElements.define("custom-tab", CustomTab);
没有ID的关系
在HTML中,id 属性表示了一个元素。举个例子,在表单中,通过将标签的 for 属性指 <input>
id,将标签属性与其对应的输入关联起来。在ARIA中,有一些属性需要指向一个 id 或多个id),比如aria-controls 和 aria-describedby。通过AOM,可以直接将元素与其他元素关联起来,而不需要指定一个 id。
正常的情况下:
el.ariaDescribedBy = "id1";
上面的代码渲染出来就变成了
<div aria-describedby="id1"></div>
草案提出可以直接将元素赋予给属性
el.ariaDescribedByElements = [labelElement1, labelElement2];
el.ariaActiveDescendantElement = ownedElement1;
*这个特性目前在 Blink 中实现了
可访问性事件
在 JavaScript 中,有点击、键盘按下和触摸等事件。在某些情况下,这些事件与辅助技术用户的输入之间存在差异。
例如拖动滑块的事件,因为屏幕阅读器用户已经使用 "向左滑动 "和 "向右滑动 "的手势来触发屏幕阅读器的特定命令,所以无法再使用相同的手势来触发其他的事件。因此 AOM 带来了一些特定的事件,以便 AT 可以设计一致的方式让用户执行某些操作,苹果将这些事件称为语义事件。为了用户隐私问题,防止恶意网站利用它们来检测某人是否有视觉或行动障碍,这些事件最终会被转换为 DOM 中的特定事件。
无障碍节点(AccessiableNode)
每个DOM元素都有一个相关的AccessibleNode,允许作者读写可访问属性。这被命名为 “可访问性对象模型”,类似于文档对象模型。
目前随着讨论的深入,这个模型依然存在一些问题。
依赖于可访问性树。
暴露计算出的可访问性树需要在不同的浏览器上对计算树的方式进行标准化。
确定ARIA属性和AccessibleNode属性的优先顺序并没有一个明显的 "正确 "答案。
同样,专门使用 AccessibleNodes 来表达关系也令人困惑。
虚拟无障碍节点(Virtual Accessibility Nodes)
虚拟无障碍节点允许开发者暴露一个虚拟的无障碍节点,这些节点不直接与任何特定的 DOM 元素相关联。
调用 attachAccessibleRoot() 会导致 AccessibleNode 与 Node 关联。返回的 AccessibleNode 形成一个虚拟可访问性树的根。一旦附加了一个 AccessibleRoot,Node的 DOM 子节点就会被隐式地忽略,以实现可访问性。
一个元素只能有一个关联的 AccessibleRoot。
只有 AccessibleNodes 可以作为 AccessibleNodes 子节点。
canvas.attachAccessibleRoot();
let table = canvas.accessibleRoot.appendChild(new AccessibleNode());
table.role = "table";
table.colCount = 10;
table.rowcount = 100;
let headerRow = table.appendChild(new AccessibleNode());
headerRow.role = "row";
headerRow.rowindex = 0;
非 DOM 节点中的可访问性树
在一些非常特殊的情况下,一个 Web 应用程序可能会包含不存在与 DOM 节点中的内容。例如在画布中的一些内容,例如在画布上绘制一个火车站的可用电梯地图,每个电梯都有一个标签,也有一个可以展开的弹窗,这些信息无法被读屏软件识别。使用AOM,你可以定义一个包含所有标签和扩展状态的无障碍树。然后这些信息将被传达给 AT(Acoustically Transparent),以便视障用户可以理解它们。
测试
虽然现在有类似于 a11y-lint 的检测工具,但是这种工具的原理是去解析 html / jsx 标签中的属性,也就是解析 DOM 树上的属性。利用 AOM 可以快速访问 HTML 节点的名称、角色(role)和无障碍状态(state)等 ARIA 无障碍属性,这个功能会让无障碍的检测变得更好。
现状
表格更新于: July 9, 2019
AOM的规范仍在制定中,实现也在进行中,各种浏览器也都实现了部分的 AOM,目前最多实现的部分是属性的映射。
如果启用 AOM 后,你可以打开这个链接,看到你的浏览器对规范中属性反射部分的支持程度。
希望以上内容对你有帮助,你可以点击链接查看草案中的细节。
AOM(Accessibility Object Model 无障碍对象模型)草案解读相关推荐
- Browser Object Model浏览器对象模型
目录 1. Window对象 2. Window Screen对象 3. Window Location对象 4. Window History对象 5. Window Navigator对象 6. ...
- Component Object Model (COM)
[简介] COM是什么?COM怎么来的?为什么要有COM?COM是怎么工作的?COM组件,COM对象,COM接口关系? COM (Component Object Model, 组件对象模型) 是一种 ...
- Sharepoint学习笔记 –架构系列—Sharepoint的客户端对象模型(Client Object Model)
前面过了一下Sharepoint的服务器端对象模型,接下来就让我们大致看看Sharepoint的客户端对象模型(Client Object Model: Client OM). 首先需要了解的就是Sh ...
- BOM—浏览器对象模型(Browser Object Model)
1,javascript 组成部分: 1.ECMAscript(核心标准): 定义了基本的语法,比如:if for 数组 字符串 ... 2.BOM : 浏览器对象模型(Browser ...
- Sharepoint学习笔记 –架构系列—12 Sharepoint的客户端对象模型(Client Object Model)
前面过了一下Sharepoint的服务器端对象模型,接下来就让我们大致看看Sharepoint的客户端对象模型(Client Object Model: Client OM). 首先需要了解的就是Sh ...
- Sharepoint学习笔记 –架构系列—10 Sharepoint的服务器端对象模型(Server Object Model) 2.内容层次结构
Sharepoint的内容层次结构(Content Hierarchy)包括表示可发布数据项(publishable items),如列表项的类,还包括表示嵌套的数据容器(nested contain ...
- 《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记
来源:http://dsqiu.iteye.com/blog/1669614 之前一直对C++内部的原理的完全空白,然后找到<Inside The C++ Object Model>这本书 ...
- BOM浏览器对象模型(Browser Object Model)
文章目录 一.BOM浏览器对象模型(Browser Object Model) window对象 window对象的方法 navigator/location/history/screen对象 nav ...
- js浏览器对象模型(Brower Object Model)
BOM:浏览器对象模型, Brower Object Model. DOM 是 W3C 的标准: [所有浏览器公共遵守的标准] BOM 是 各个浏览器厂商根据 DOM在各自浏览器上的实现;[表现为不同 ...
最新文章
- 总市值3862亿的创始人们在各阶段是怎么选女友的?
- 推荐系统常用术语 [ACM暑校]
- 如何使用git上传本地文件到码云上【详细步骤】
- 学习数字图像处理经验谈
- apache camel_您的Apache Camel应用程序现在包括现成的文档
- SpringBoot 整合ActiveMQ_企业实战
- 同步异步 阻塞非阻塞
- JavaScript 代码判断:PC端和手机端
- 机器视觉及图像处理系列之二(C++,VS2015)——图像级的人脸识别(1)
- 苹果首席设计官将离职;华为将从世界范围招揽天才少年;新版 Edge 更新 | 极客头条...
- Clang与LLVM的关系
- vmware fusion 文件共享_颜值至上,杜伽fusion我是真的被它的颜值吸引了
- paip.c++ qt 网页爬虫 的 网络编程 总结
- BXP无盘Windows XP网吧系统的好处(转)
- 微信公众号选择什么服务器好,微信开发选择订阅号还是服务号好?
- Java——TCP/IP超详细总结
- C++之策略(Strategy)模式
- #蓝桥杯真题【思特奇杯·云上蓝桥-算法集训营】第2周
- 网络流建图方法(二)——辅助点(虚点)决策法洛谷 P1361 小M 的作物 Dinic
- 基于Java的亚马逊“手机”评论爬虫的情感分类分析
热门文章
- 我期待的科研生活作文英文作文
- 2022年夏季《移动软件开发》实验报告三
- 华为鸿蒙电视销量,华为电视将采用纯国产方案:京东方面板+海思芯片+鸿蒙系统...
- c语言scanf错误c4996,C语言杂谈(一)scanf()、scanf_s()与错误 C4996
- Ogre下的OpenVR开发(1)---Openvr的缺陷
- 【30秒】去除360浏览器“网页走丢了/网页无法访问“页面的垃圾广告!----2021.03.09
- 有什么古装特效照片软件?建议收藏这些软件
- linux下oracle安装路径查看,Linux Oracle 安装目录说明
- 7-20 棋盘覆盖 (10 分)
- vcs学习 (dev波形)