4.1 无障碍树原理:比 DOM 干净、比截图便宜


4.1 无障碍树原理:比 DOM 干净、比截图便宜

本节摘要:本节讲结构化快照流派的表示层基础。无障碍树是浏览器在渲染之外维护的第二棵树:从 DOM 计算出的语义结构,每个节点携带角色(按钮、链接、标题)、名称(可见文本或标签)、状态(选中、展开),服务于屏幕阅读器等辅助技术——它是对页面「语义骨架」的权威描述。干净:DOM 里三层嵌套容器、样式类名、脚本属性全是模型不需要的噪音,无障碍树只留语义节点,同样的页面 token 少一到两个数量级。便宜:文本表示的输入成本远低于图像,且每个节点有稳定身份可被引用(ref),模型指名道姓地操作元素而不必报坐标。对照表把 DOM、截图、无障碍树放进同一坐标系;局限部分诚实列出它读不出的东西——Canvas、无语义标记、纯图像按钮——并给出对策(补语义标记,或转视觉流派)。

学习目标

  • 说出无障碍树的节点构成(角色、名称、状态)与它的原生服务对象。
  • 解释「比 DOM 干净」与「比截图便宜」各自的机制原因。
  • 用三表示对照表为给定任务选择页面表示。
  • 列出无障碍树读不出的四类内容与各自对策。

一、无障碍树是什么

浏览器渲染一个页面,其实维护着多棵树:DOM 树(源码结构)、渲染树(布局与绘制),以及一棵常被开发者忽略的无障碍树(accessibility tree,社区常缩写 a11y tree)。它是浏览器从 DOM 计算出的语义结构:剥离呈现细节,只回答「这个页面对辅助技术来说是什么」。每个节点携带三类核心信息:

构成 含义 靶场示例
角色 这是什么类型的元素 按钮、文本框、链接、列表
名称 用户怎么识别它 「添加」「新待办」「关于」
状态 它现在处于什么状态 已选中、展开、必填、禁用
DOM 树(源码视角) 无障碍树(语义视角) 文档 文档 ├─ 容器(样式类) ├─ 标题「今天要做的事」 │ └─ 容器(布局类) ├─ 文本框「新待办」 │ ├─ 标题文字 ├─ 按钮「添加」 │ ├─ 输入框 ├─ 列表「待办清单」 │ ├─ 按钮(多层嵌套) │ └─ 列表项「暂无待办」 │ └─ 列表 … └─ 链接「关于」 (带样式、脚本、嵌套噪音) (只剩语义骨架) ​

关键认知:这棵树不是为 AI 发明的。屏幕阅读器靠它向视障用户播报页面,键盘导航、读屏软件、系统级辅助 API 全在消费它——页面语义质量原本就是无障碍工程的质量。WAI-ARIA 这套标记语言的存在意义就是让开发者把语义补进 DOM。浏览器智能体只是这条消费链上的新成员,因此「快照可读性」与「无障碍友好」是同一件事:一个对读屏用户友好的页面,天然就是对模型友好的页面。

二、亲眼看到它:两种查看方式

不信「干净」的最好方式是亲眼看。方式一:Chrome 开发者工具的元素面板里有无障碍侧栏,选中任一元素可以看到它在无障碍树中的角色、名称与状态;方式二:用驱动库直接取页面的语义快照(Playwright 提供了对应的序列化能力,接口名以官方文档为准):

# aria_snapshot.py —— 打印页面的语义快照(写法示意,接口以官方文档为准) import asyncio from playwright.async_api import async_playwright async def main() -> None: async with async_playwright() as p: browser = await p.chromium.launch(headless=True) page = await browser.new_page() await page.goto("http://127.0.0.1:8080/demo_todo.html") snapshot = await page.locator("body").aria_snapshot() print(snapshot) await browser.close() asyncio.run(main()) ​

对靶场页面的期望输出(示意,缩进体现层级——这正是第 4.2 节 MCP 快照的雏形形态):

# aria_snapshot_output.txt —— 语义快照输出示意 - heading "今天要做的事" [level=1] - textbox "新待办" - button "添加" - list: - listitem "暂无待办" - link "关于" ​

六行文本说完一页——把它与开发者工具里源码视图的行数对比,「干净」就不再是抽象形容。建议此刻动手做一遍:往后所有章节里「快照长什么样」的讨论,都有了实感锚点。

三、为什么比 DOM 干净

DOM 是给浏览器的,不是给语义理解 的。它包含:样式类名与内联样式、脚本钩子与数据属性、为布局服务的嵌套容器(一个按钮的源码可能裹在三四层容器里)、以及视口外或隐藏的元素。这些对渲染引擎是必需信息,对「找到添加按钮」这个任务全是噪音。

无障碍树天然完成四重过滤:结构过滤——布局容器不进语义树,只有承担角色的节点进;可见性过滤——隐藏元素(对辅助技术不可见的)被剔除,与第 1.2 节「用户看不见的不该点」原则自动对齐;命名解析——输入框的关联标签被解析成它的名称,模型看到的不再是裸输入框而是「新待办输入框」;状态注入——选中、展开、禁用等动态状态直接标注在节点上,不必从属性推断。

量化感受(示意量级,以实际页面为准):第 0.2 节靶场页面的 DOM 源码数百行,无障碍树序列化后约十行(上一节的输出就是实物);真实复杂页面的差距更悬殊,且页面越复杂、DOM 越臃肿,快照的相对优势越大。拿一个常见量级做心算锚点:中型电商首页的 DOM 转文本可达数十万字符,其无障碍树序列化通常只有数千——差两个数量级;而整页截图的视觉输入折算后,又普遍是快照的数倍。三个数量级的落差解释了为什么「用哪种眼睛」是浏览器智能体的第一选型题。

四、为什么比截图便宜

便宜体现在三笔账。输入成本:文本的模型输入成本按字符计,图像按块计——一张 1080p 截图的输入成本通常是等价语义文本快照的数倍(第 5.1 节有完整对比)。引用成本:截图上指认元素只能报坐标,坐标随窗口尺寸与滚动漂移;快照上每个元素有稳定身份(框架为节点分配的 ref),模型说「操作 ref 为 e5 的按钮」,精确且不随布局变。生产成本:截图要传输、存储、标注(SoM 一类,第 5.1 节),快照是纯文本,日志、缓存、diff 全套工具链免费可用。

三笔账合成一张选型表(本章的页面表示决策依据,第 5.1 节会扩展它):

维度 DOM 无障碍树 截图
token 成本 高 低 数倍于快照
语义表达 弱(需自行解析) 强(原生语义) 中(靠模型识别)
元素引用 选择器 ref(稳定、结构化) 坐标(易漂移)
布局与图像信息 无 无(仅语义) 有(独占)
适用 固化代码路径 交互驱动的默认表示 Canvas、图片、无语义页面

注意无障碍树的一处硬短板:它不包含布局与视觉信息——两个按钮谁在左边、图标长什么样、图表画了什么,快照一概不知。这些信息只有截图有,这决定了结构化与视觉是互补表示而非竞争表示。由此还能推出一个反直觉的推论:快照质量取决于页面的语义质量,与页面好不好看无关——一个视觉简陋但标记规范的页面,快照可能极其干净;一个获奖设计但语义欠账的页面,快照可能一塌糊涂。评估「这个页面好不好自动化」时,先看语义,别看颜值。

五、局限:快照读不出的东西

局限场景 快照里长什么样 对策
Canvas / WebGL 内容 一块「画布」角色,无内部结构 视觉流派(第 5 章)
图片按钮(无替代文本) 名称缺失的图形节点 页面侧补替代文本;或视觉流派
无语义标记的自绘控件 容器节点,无角色无名 页面侧补语义标记;或视觉流派
动态更新频繁的页面 快照是某时刻的切面,随口延迟过期 快照后立即消费;动作后强制刷新快照

前三种的公共根因是页面语义欠账:开发者没做无障碍标记,快照就无米下炊。这给技术选型加了一条现实判据:对自家页面,优先补语义标记(一劳永逸地改善快照、读屏与 SEO 三件事);对他人的欠账页面,别指望快照,直接评估视觉流派。第四种是时序问题,Playwright MCP 的工作流用「每次动作后重新快照」应对(第 4.2 节),代价是每轮都付一次快照成本。

一个亲手可做的对照实验(十分钟):给靶场页面的「添加」按钮临时加一个纯图标版本(去掉文字,只留图形),分别跑上一节的语义快照脚本与肉眼截图——快照里它会退化成一个无名按钮(或干脆消失于语义层),截图里它仍然醒目。这个小实验同时演示了两种表示的盲区与强区,比读十页文档更直观;它也是第 5.1 节「视觉是唯一解」清单的最小复现装置。

六、快照的两种工程来源

工程语境里的「快照」其实有两个来源,分清它们有助于理解各家工具的差异:来源一是浏览器计算的无障碍树——浏览器渲染时自行维护,驱动库通过调试协议或无障碍接口读取(第二节脚本背后正是它);来源二是驱动库序列化的语义快照——按自家的行文规范把树整理成带缩进、带 ref 的文本(第二节输出与第 4.2 节 MCP 快照都是这类)。差异类比:前者是原始档案,后者是按模板誊抄的简报——信息同源,但誊抄模板决定了模型读到什么:ref 怎么编号、层级压到多深、隐藏元素如何呈现,各家实现并不一致。

这解释了一个实践现象:同一个页面,不同框架的「快照」看起来长相不同、大小也不同,但都自称无障碍树快照——比的不是谁更真,而是谁的模板更适合自家模型消费。读者侧的结论有两条:评估框架时别只看快照大小,要看它在你的目标页面上保留了哪些语义;迁移框架时,快照模板差异是首要适配点(第 6 章的回归任务集因此要按框架分别建基线)。

两种来源也提示了排查快照问题时的分叉:语义在快照里缺失,先问「页面有没有做标记」(来源侧欠账),再问「模板有没有滤掉它」(誊抄侧取舍)——前者要改页面,后者要换工具或调模板,改错了对象白费功夫。用第二节的方法亲眼对照「开发者工具里的树」与「驱动库序列化的快照」,两问立判。

本节要点回顾

  • 无障碍树是浏览器维护的语义结构(角色、名称、状态),原生服务对象是辅助技术,模型是新成员。
  • 干净的来源:结构过滤、可见性过滤、命名解析、状态注入四重机制。
  • 便宜的三笔账:文本输入成本、ref 稳定引用、纯文本工具链。
  • 硬短板:不含布局与视觉信息,Canvas 与无语义页面读不出——互补而非竞争于截图。
  • 快照可读性与无障碍友好是同一件事;自家页面补语义,他人页面转视觉。
  • 快照质量取决于页面语义质量,与视觉颜值无关;评估自动化难度先看语义。
  • 快照有两种工程来源(浏览器计算的树与驱动库的序列化模板),排查缺失先分清是页面欠账还是模板取舍。
  • 亲眼验一次:开发者工具的无障碍侧栏与第二节脚本的输出对照着看,「干净」就有了实感。

表示层讲完,接下来看它如何变成一个 Agent 可用的服务器:下一节讲 Playwright MCP——微软官方把无障碍快照与浏览器操作封装成 MCP 工具,让编码 Agent 用 ref 引用元素完成驱动。

作者与出处
原作者:灏天文库
整理人: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U