Chrome 开发者工具中的完整无障碍功能树

Johan Bay
Johan Bay

Chrome 开发者工具将推出一个完整的无障碍功能树,让开发者能够更轻松地掌握整个无障碍功能树的概况。在这篇博文中,您将了解这个树是如何创建的,以及如何在您的工作中使用它。

什么是无障碍树?

屏幕阅读器等辅助技术使用 Chromium 的无障碍功能 API 与 Web 内容互动。此 API 的基本模型是无障碍树:辅助技术可以查询属性和属性并对其执行操作的无障碍对象树。网络开发者主要通过 DOM 属性(例如 HTML 的 ARIA 属性)来塑造和操纵无障碍树。

Chrome 开发者工具中,我们提供了无障碍功能窗格来帮助开发者了解其内容会如何暴露给辅助技术。具体而言,在 DOM 树查看器中选择节点时,相应无障碍节点的属性会连同该节点的祖先及其直接子项的视图一起显示在窗格中。

Chrome DevTools 无障碍功能窗格。

树是如何创建的?

在了解这种全新的完整树状视图在开发者工具中的样子之前,我们先简单了解一下无障碍树的定义。无障碍树是 DOM 树的衍生作品。其结构大致相同,但经过简化,移除没有语义内容的节点(例如仅用于样式设置的 <div> 元素)。树状结构中的每个节点都有一个诸如 ButtonHeading 之类的角色,通常还有一个名称可以来自 ARIA 属性,也可以来自节点的内容。如果我们查看 HTML 文档:

<html>
<head>
  <title>How old are you?</title>
</head>
<body>
  <label for="age">Age</label>
  <input id="age" type="number" name="age" value="42">
  <div>
    <button>Back</button>
    <button>Next</button>
  </div>
</body>
</html>

Chromium 中的渲染程序 Blink 大致如下派生了一个内部无障碍功能树。

role='rootWebArea' focusable name='How old are you?'
  role='genericContainer' ignored
    role='genericContainer' ignored
      role='labelText'
        role='staticText' name='Age'
      role='spinButton' editable focusable name='Age' value='42'
        role='genericContainer' editable
          role='staticText' editable name='42'
      role='genericContainer'
        role='button' focusable name='Back'
          role='staticText' name='Back'
        role='button' focusable name='Next'
          role='staticText' name='Next'

请注意,此表示法包含多个具有 genericContainer 角色的多余节点,这似乎与上述关于无障碍树是 DOM 树的简化派生的说法相矛盾。尽管如此,这些节点大多仅出现在内部树中,不会提供给辅助技术。由于开发者工具直接从渲染器进程收集其无障碍功能信息,因此这是开发者工具所处理的树状表示形式。

开发者工具中的完整无障碍功能树

全新的完整无障碍树可与 DOM 树同步,因此开发者可以在这两种树之间来回切换。我们希望这款新树将变得更易于探索、更实用且更易于使用。

现在,您已了解无障碍树的工作原理,您可以使用开发者工具来查看新树状视图的外观。以下 HTML 文档使用了标题、标题和两个按钮来显示树。

<!DOCTYPE html>
<title>Test</title>
<h1>Heading for example page</h1>
<div>
  <button>Back</button>
  <button>Next</button>
</div>

之前的树状视图只能探索单个节点及其祖先实体。

开发者工具中的上一个树状视图。

现在,当您切换新树时,它会取代 DOM 树视图,并允许您查看页面的完整无障碍功能树:

DevTools 中的新树状视图。

懒懒的树构建

为使该树在较大的站点上也能保持良好的性能,在探索该树时,会在前端延迟构造该树。节点在树中展开后,系统会通过 Chrome 开发者工具协议 (CDP) 获取节点的子级,然后重新构建树。

显示大页面结果的全新无障碍功能树。

直播

新的树状视图是实时的,如果渲染程序中的无障碍树发生变化,系统会动态更新。它接入至向辅助技术发送树更改通知的相同机制,并使用该机制向具有更新节点的开发者工具前端发送事件。 实际上,CDP 后端会监听树的更新,跟踪之前请求了哪些节点,并在任何节点发生变化时将事件发送到开发者工具前端。

关于许多树木的故事

什么是无障碍功能树的说明中,您学习了 Blink 如何为它正在渲染的 DOM 构建无障碍功能树,而开发者工具会通过 CDP 获取此树。虽然这是事实,但我们在说明中略去了一些复杂问题。实际上,在 Chromium 中,您可以通过多种不同的方式体验无障碍树。 在为开发者工具设计新的树状视图时,我们已经对想要呈现 Chromium 无障碍功能内部的哪些方面作出了一些选择。

平台

每个平台都有不同的无障碍功能 API,尽管树的形状在所有平台上都是相同的,但用于与树进行交互的 API 则不同,并且属性的名称可以不同。开发者工具会显示 Chromium 的内部树,其中角色和属性往往与 ARIA 规范中定义的角色和属性相匹配。

多框架和网站隔离

由于 Chromium 不仅会将每个标签页的内容放在不同的渲染程序进程中,还会在不同的渲染程序进程中隔离跨网站文档,因此我们必须通过 CDP 单独连接到每个进程外子文档,并提取其无障碍树。然后,我们将这些子树拼接到前端,以呈现一个连贯树的错觉,尽管它们在 Chromium 中位于不同的渲染程序进程中。

被忽略的节点和不感兴趣的节点

我们会按默认设置隐藏一些节点:被忽略的节点以及角色为“generic”但无名称的节点。这些节点没有语义含义,并且对于被忽略的节点,不会接触辅助技术。我们会隐藏这些节点,以避免树状视图杂乱无章。否则,大多数网页的无障碍树会变为如下形式:

显示所有节点的新树状视图。

需要注意的是,这实质上意味着,我们需要构建另一个树,而不是后端可用的树。例如,假设我们有节点 A、B、C 和 X,其中 A 有子节点 X 和 B,X 有子节点 C。如果 X 是忽略的节点,我们将从该树中删除 X,并改为创建一个 C 是 A 的子节点的树。

展示我们如何修剪树的图表。

在前端,我们构建包含忽略的节点的完整树,并且仅在渲染节点之前剪除它们。我们这样做有两个原因:

  • 这大大简化了来自后端的节点更新处理,因为两个端点具有相同的树结构。例如,如果在本例中移除节点 B,我们将收到节点 X 的更新(因为其子节点已更改),但如果我们剪掉了该节点,就很难确定要更新的内容。
  • 它确保了所有 DOM 节点都有对应的无障碍节点。切换树时,我们选择与 DOM 树中当前选择的节点对应的节点。因此,对于上述示例,如果用户在选中了 X 对应的 DOM 节点时切换树,我们会在节点 A 和 B 之间注入 X,然后在树中选择 X。这可让用户检查所有 DOM 节点的无障碍功能节点,并帮助确定忽略该节点的原因。

未来的创意

发布新的无障碍树只是一个开始。对于今后可以根据新视图进行的项目,我们有一些建议,但我们也热切希望听到大家的反馈意见

备选过滤条件

如上所述,我们目前会过滤掉我们认为无意义的节点。我们可以提供一种方式来停用此行为并显示所有节点,也可以提供替代过滤条件,例如“显示地标节点”或“显示标题”。

突出显示无障碍相关问题

我们可以将“无障碍功能最佳做法”分析整合到树中,并直接在违规节点上突出显示无障碍功能问题。

在开发者工具中显示无障碍操作

我们目前显示的纯单向树:它让我们了解在浏览特定网页时,哪些信息会被馈送给辅助技术。无障碍操作代表相反方向的通信:它们允许辅助技术对呈现的界面执行操作。我们可以在开发者工具中显示此类操作,以便使用适用于辅助技术的 API 执行“点击”、滚动或更改页面上的值等操作。