html无原生元素,需用div+aria模拟树形控件;关键在于tree/treeitem/group角色严格嵌套、aria-level显式声明、aria-expanded与aria-hidden同步控制可见性、支持home/end/方向键导航、treeitem自身聚焦且层级动态更新。

HTML 原生没有 <tree></tree> 元素,靠 div + ARIA 模拟树形控件时,无障碍支持不达标是常态——根本原因不是没加 role="tree",而是节点角色、状态、键盘交互、焦点管理四者没对齐。
tree / treeitem / group 角色必须严格嵌套
常见错误是把所有节点都设成 role="treeitem",漏掉容器语义。正确结构必须是:role="tree" 包裹若干 role="treeitem",子节点用 role="group"(不是 role="tree")包裹下级 treeitem。
例如:
<div role="tree" aria-label="文件目录">
<div role="treeitem" aria-expanded="true" aria-level="1">
<span aria-hidden="true">?</span> src
<div role="group">
<div role="treeitem" aria-level="2">index.html</div>
<div role="treeitem" aria-level="2">main.js</div>
</div>
</div>
</div>
-
aria-level必须显式声明,不能靠缩进或 CSS 推断 -
role="group"是唯一合法的子容器角色;用div或ul不加 role 会破坏树形语义 - 每个
treeitem必须有可聚焦的元素(如button或带tabindex="0"的span),否则屏幕阅读器无法选中
aria-expanded 和 aria-hidden 要同步控制子节点可见性
折叠/展开状态仅靠 CSS display: none 不够,必须配合 aria-expanded="false" 和 aria-hidden="true" 双重标记,否则 NVDA/JAWS 仍会朗读隐藏节点。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 点击展开时:设
aria-expanded="true",移除子group的aria-hidden - 点击折叠时:设
aria-expanded="false",给子group加aria-hidden="true" - 不要只操作 CSS;
aria-hidden="true"必须写在role="group"容器上,而非内部treeitem
键盘交互必须支持 Home/End/→/←/↑/↓ 六个方向键
仅实现 Tab 键跳转不够。树形控件的 WCAG 2.1 要求必须响应标准树导航键:按 → 展开当前项(若可展开),按 ← 折叠,Home/End 跳首尾,↑/↓ 线性遍历同级。
- 监听
keydown事件,对event.key做精确匹配(如"ArrowRight",不是"right") - 按 ↓ 键时,焦点应移到下一个同级
treeitem;若无,则停在末尾,不跳到父级 - 按 → 键时,先检查
aria-expanded="false"且存在role="group"子容器,再展开并聚焦第一个子treeitem - 所有键盘操作后,必须手动调用
element.focus(),不能依赖浏览器默认行为
focusable 元素必须和 treeitem 语义一致
很多人用 <button></button> 包裹整个 treeitem 内容,但按钮语义会覆盖 treeitem,导致屏幕阅读器报“按钮”而非“树项”。正确做法是让 treeitem 自身可聚焦。
- 给
div[role="treeitem"]加tabindex="0",内部用span或button仅处理展开/操作逻辑 - 展开按钮(如 ▶️)要加
aria-controls="id-of-group",指向对应role="group"的 id - 避免在
treeitem上同时放多个tabindex="0"元素,否则焦点顺序错乱 - 用
document.activeElement检查焦点是否真落在treeitem上,而不是其子按钮里
最常被忽略的是:树节点的 aria-level 值必须随 DOM 嵌套深度实时更新,不能写死。动态增删节点后,如果忘了重算层级,JAWS 就会把三级节点读成一级——这种问题只有真实用 NVDA 配合键盘导航才能暴露出来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










