+是原生可折叠结构最优解,无需JS即可展开/折叠、语义正确、屏幕阅读器可读、打印PDF不错位;关键约束:必须为首个且唯一子元素,否则箭头不显、点击失效。

用 <details></details> + <summary></summary> 实现原生可折叠结构
不用写 JS 就能展开/折叠、语义正确、屏幕阅读器能读、打印 PDF 不错位——这是目前最稳的方案。很多人一上来就手写 display: none 切换,结果键盘用户按空格没反应、Chrome 打印时所有子项全展开、IE11 下状态不同步,全是白忙。
关键约束必须守住:
-
<details></details>必须直接包裹一个且仅一个<summary></summary>,且<summary></summary>是第一个子元素,否则原生箭头不显示、点击无效 - 嵌套合法,但浏览器不会自动缩进,得靠 CSS 控制:统一用
margin-left: 1.2rem,别用padding-left,避免热区偏移和打印错位 - 禁用
white-space: nowrap,否则中文长路径或 URL 在小屏上横向溢出,布局直接崩 - 文字过长时加
word-break: break-word,防止断在<script></script>或https://中间
连线与图标必须用伪元素,不能塞 Unicode 或 <img alt="HTML树形菜单导航如何布局?层级关系搭建教程" >
想画树形竖线+横线组成的「T」形?千万别用 <div class="line"> 或 Unicode 字符(如 <code>└、├)。这些在 Safari 渲染模糊、等宽字体下偏移、打印时直接消失。
正确做法是纯 CSS 伪元素控制:
立即学习“前端免费学习笔记(深入)”;
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
- 竖线:用
<summary>::before</summary>,设position: absolute; left: -16px; top: 0; height: 100%; border-left: 1px solid #999 - 横线:只加在最后一个子项的
<details>::after</details>,content: ""+position: absolute; left: -16px; top: 50%; width: 16px; border-top: 1px solid #999 - 图标统一走
<summary>::marker</summary>或::before,禁用transform: scaleY(-1)类翻转技巧——Chrome 打印时会丢掉
如果必须用 <ul></ul> + JS,ARIA 状态和键盘逻辑不能省
手写 ul 嵌套看似灵活,但一旦跳过 ARIA 和键盘支持,就是残障用户不可用、SEO 不识别、测试过不了。尤其当菜单用于后台系统或政务网站时,这步绕不开。
常见硬伤:
- 把子
<ul></ul>提到同级位置,破坏role="tree"语义嵌套 - 忘记给每个
<li>加role="treeitem",屏幕阅读器直接跳过整段 - 用
display: none隐藏子菜单,导致内容被读屏器忽略;应改用aria-hidden="true"+visibility: hidden或height: 0 - 没监听
ArrowRight/ArrowLeft:展开/收起必须支持键盘操作,否则 WCAG 2.1 AA 不达标
层级深了之后,DOM 顺序和缩进精度比“能嵌几层”更重要
嵌套本身没有浏览器限制,但人眼识别层级依赖两个稳定信号:缩进像素一致、连线对齐无偏移。哪怕只嵌 4 层,若某级用了 margin-left: 1.5rem、另一级用了 1.2rem,视觉上就会“断层”,用户瞬间迷失。
实操建议:
- 所有缩进统一用
margin-left,值固定为1.2rem(不要用 em 或 %,防字体缩放错位) - 每级
<details></details>的::before和::after的left、top、width必须严格对应,差 1px 都会导致连线错位 - 打印前务必测试 PDF 输出:Chrome 的“另存为 PDF”会重置 JS 控制的状态,但
<details open></details>能保留,这是唯一可靠锚点


















