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

为什么不能用
堆多级目录结构
语义断裂是第一道坎。<p>不带任何层级或顺序含义,屏幕阅读器会把它读成“一堆文字”,无法识别“第3章→3.2节→3.2.1小节”这种天然序贯关系;搜索引擎也难以提取结构化数据。更实际的问题是:CSS 选择器如 li:hover > ul 依赖 DOM 层级嵌套,<p> 套 <p> 会让 hover 状态丢失、键盘 Tab 焦点流错乱、移动端点击区域失效。
- 必须用
<ol>包裹一级目录项——它提供原生编号、start和type控制,且语义上明确“章节有固定次序” - 子级仍用
<ol>(不是<ul>),因为“3.2.1”仍是有序编号,不是无序列表 - 每个
<li>内必须直接包裹<a href="#id">文本</a>,不能只包<span>或空链接,否则辅助技术无法关联标题与跳转目标
多级 <ol> 嵌套的 DOM 结构硬约束
浏览器对嵌套合法性很敏感。子 <ol> 必须作为父 <li> 的**直接子元素**,不能写在父 <li> 外面,也不能塞进 <span> 或 <p> 中间。一旦错位,CSS 伪类(如 ol ol)和 JS 查询(如 el.querySelectorAll('ol > li'))都会漏掉节点。
- 正确:
<li><a href="#sec3">第三章</a><ol><li><a href="#sec3-1">3.1 节</a></li></ol></li> - 错误:
<li><a href="#sec3">第三章</a></li><ol><li><a href="#sec3-1">3.1 节</a></li></ol>(子<ol>脱离父<li>) - 锚点
id必须唯一、全小写、不含空格或特殊符号,且与对应章节的id完全一致(大小写敏感)
响应式折叠交互该用 <details> 还是纯 CSS
<details> 看似省事,但 Safari 旧版、部分安卓 WebView 对 open 属性响应不稳定,打印 PDF 时状态重置,且无法精确控制动画缓动。真正在生产环境跑得稳的,还是 CSS + 少量 JS:用 max-height 过渡模拟展开收起,JS 只负责切换 aria-expanded 和焦点管理。
- 一级目录项加
role="heading" aria-level="1",子级按深度递增aria-level - 折叠按钮用
<button type="button">而非<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>的最后一个<li>上,用li:last-child::after画短横线,避免层级累积偏移 - 超过三层嵌套(如 2.1.1.1)视觉负担陡增,建议用
<details>折叠中间层,而非强行展开
实际最难的部分不是写出能动的菜单,而是让编号语义、焦点顺序、缩进像素、连线位置,在 Chrome/Firefox/Safari、桌面/平板/PDF 导出、放大字体/高对比度模式下全部对齐——这些细节一旦写错,调试成本远高于重写结构。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/123981.html