必须用而非实现多级目录,因提供原生顺序语义、屏幕阅读器支持及编号控制;子须为父直接子元素,锚点id须唯一匹配,缩进与连线需用margin-left和伪元素绝对定位确保跨场景稳定。

为什么不能用堆多级目录结构
语义断裂是第一道坎。<div>不带任何层级或顺序含义,屏幕阅读器会把它读成“一堆文字”,无法识别“第3章→3.2节→3.2.1小节”这种天然序贯关系;搜索引擎也难以提取结构化数据。更实际的问题是:CSS 选择器如 <code>li:hover > ul 依赖 DOM 层级嵌套,<div> 套 <code><div> 会让 hover 状态丢失、键盘 <code>Tab 焦点流错乱、移动端点击区域失效。
- 必须用
<ol></ol> 包裹一级目录项——它提供原生编号、start 和 type 控制,且语义上明确“章节有固定次序”
- 子级仍用
<ol></ol>(不是 <ul></ul>),因为“3.2.1”仍是有序编号,不是无序列表
- 每个
<li> 内必须直接包裹 @#@#@#@#@#@#@#@#@#@0,不能只包 <span></span> 或空链接,否则辅助技术无法关联标题与跳转目标
多级 <ol></ol> 嵌套的 DOM 结构硬约束
浏览器对嵌套合法性很敏感。子 <ol></ol> 必须作为父 <li> 的**直接子元素**,不能写在父 <li> 外面,也不能塞进 <span></span> 或 <div> 中间。一旦错位,CSS 伪类(如 <code>ol ol)和 JS 查询(如 el.querySelectorAll('ol > li'))都会漏掉节点。
- 正确:
<li>@#@#@#@#@#@#@#@#@#@1<ol><li>@#@#@#@#@#@#@#@#@#@2</li></ol>
</li>
- 错误:
<li>@#@#@#@#@#@#@#@#@#@1</li>
<ol><li>@#@#@#@#@#@#@#@#@#@2</li></ol>(子 <ol></ol> 脱离父 <li>)
- 锚点
id 必须唯一、全小写、不含空格或特殊符号,且与对应章节的 id 完全一致(大小写敏感)
响应式折叠交互该用 <details></details> 还是纯 CSS
<details></details> 看似省事,但 Safari 旧版、部分安卓 WebView 对 open 属性响应不稳定,打印 PDF 时状态重置,且无法精确控制动画缓动。真正在生产环境跑得稳的,还是 CSS + 少量 JS:用 max-height 过渡模拟展开收起,JS 只负责切换 aria-expanded 和焦点管理。
- 一级目录项加
role="heading" aria-level="1",子级按深度递增 aria-level
- 折叠按钮用
<button type="button"></button> 而非 <a></a>,避免误触发页面跳转
- CSS 动画禁用
height: auto 过渡(不支持),改用 max-height: 0 → max-height: 500px(设足够大值)
- 移动端需监听
touchstart 并 preventDefault(),防止快速点击时触发两次
缩进与连线样式在不同场景下的稳定性陷阱
用 padding-left 控制缩进,在 IE11、打印 PDF、字体缩放时容易错位;用 transform: translateX() 画连线,Chrome 打印时直接消失。真正跨场景稳定的方案,是回归标准盒模型 + 伪元素绝对定位。
- 缩进统一用
margin-left: 1.5em(不是 px),配合 display: flex 容器防塌陷
- 垂直连线用
li::before:设 position: absolute; left: -16px; top: 0; height: 100%; border-left: 1px solid #999
- 水平连线只加在每个
<ol></ol> 的最后一个 <li> 上,用 li:last-child::after 画短横线,避免层级累积偏移
- 超过三层嵌套(如 2.1.1.1)视觉负担陡增,建议用
<details></details> 折叠中间层,而非强行展开
实际最难的部分不是写出能动的菜单,而是让编号语义、焦点顺序、缩进像素、连线位置,在 Chrome/Firefox/Safari、桌面/平板/PDF 导出、放大字体/高对比度模式下全部对齐——这些细节一旦写错,调试成本远高于重写结构。
语义断裂是第一道坎。<div>不带任何层级或顺序含义,屏幕阅读器会把它读成“一堆文字”,无法识别“第3章→3.2节→3.2.1小节”这种天然序贯关系;搜索引擎也难以提取结构化数据。更实际的问题是:CSS 选择器如 <code>li:hover > ul 依赖 DOM 层级嵌套,<div> 套 <code><div> 会让 hover 状态丢失、键盘 <code>Tab 焦点流错乱、移动端点击区域失效。
- 必须用
<ol></ol>包裹一级目录项——它提供原生编号、start和type控制,且语义上明确“章节有固定次序” - 子级仍用
<ol></ol>(不是<ul></ul>),因为“3.2.1”仍是有序编号,不是无序列表 - 每个
<li>内必须直接包裹@#@#@#@#@#@#@#@#@#@0,不能只包<span></span>或空链接,否则辅助技术无法关联标题与跳转目标
多级 <ol></ol> 嵌套的 DOM 结构硬约束
浏览器对嵌套合法性很敏感。子 <ol></ol> 必须作为父 <li> 的**直接子元素**,不能写在父 <li> 外面,也不能塞进 <span></span> 或 <div> 中间。一旦错位,CSS 伪类(如 <code>ol ol)和 JS 查询(如 el.querySelectorAll('ol > li'))都会漏掉节点。
- 正确:
<li>@#@#@#@#@#@#@#@#@#@1<ol><li>@#@#@#@#@#@#@#@#@#@2</li></ol> </li> - 错误:
<li>@#@#@#@#@#@#@#@#@#@1</li> <ol><li>@#@#@#@#@#@#@#@#@#@2</li></ol>(子<ol></ol>脱离父<li>) - 锚点
id必须唯一、全小写、不含空格或特殊符号,且与对应章节的id完全一致(大小写敏感)
响应式折叠交互该用 <details></details> 还是纯 CSS
<details></details> 看似省事,但 Safari 旧版、部分安卓 WebView 对 open 属性响应不稳定,打印 PDF 时状态重置,且无法精确控制动画缓动。真正在生产环境跑得稳的,还是 CSS + 少量 JS:用 max-height 过渡模拟展开收起,JS 只负责切换 aria-expanded 和焦点管理。
- 一级目录项加
role="heading" aria-level="1",子级按深度递增aria-level - 折叠按钮用
<button type="button"></button>而非<a></a>,避免误触发页面跳转 - CSS 动画禁用
height: auto过渡(不支持),改用max-height: 0→max-height: 500px(设足够大值) - 移动端需监听
touchstart并preventDefault(),防止快速点击时触发两次
缩进与连线样式在不同场景下的稳定性陷阱
用 padding-left 控制缩进,在 IE11、打印 PDF、字体缩放时容易错位;用 transform: translateX() 画连线,Chrome 打印时直接消失。真正跨场景稳定的方案,是回归标准盒模型 + 伪元素绝对定位。
- 缩进统一用
margin-left: 1.5em(不是px),配合display: flex容器防塌陷 - 垂直连线用
li::before:设position: absolute; left: -16px; top: 0; height: 100%; border-left: 1px solid #999 - 水平连线只加在每个
<ol></ol>的最后一个<li>上,用li:last-child::after画短横线,避免层级累积偏移 - 超过三层嵌套(如 2.1.1.1)视觉负担陡增,建议用
<details></details>折叠中间层,而非强行展开











