嵌套有序列表(OL)出现严重重叠,主列表项(1、2、3…)挤在同一垂直位置,子项(1.1、1.1.1…)虽结构正确却层叠堆叠——根本原因是错误地对 <ol> 应用了 position: fixed 和 counter-reset,导致所有列表项脱离文档流并共享同一计数器作用域。
嵌套有序列表(ol)出现严重重叠,主列表项(1、2、3…)挤在同一垂直位置,子项(1.1、1.1.1…)虽结构正确却层叠堆叠——根本原因是错误地对 `
- ` 应用了 `position: fixed` 和 `counter-reset`,导致所有列表项脱离文档流并共享同一计数器作用域。
该问题并非 JavaScript 逻辑或 HTML 结构缺陷,而是 CSS 布局规则被误用所致。核心症结在于以下两行样式:
ol {
position: fixed; /* ❌ 错误:使所有 ol 脱离文档流,定位到视口固定位置 */
counter-reset: item; /* ❌ 错误:在顶层 ol 上重置计数器,子 ol 无法独立继承/重置 */
}当 position: fixed 应用于 <ol> 元素时,它会脱离正常文档流,不再占据空间,且所有嵌套 <ol>(如 <li><ol>...</ol></li> 中的子列表)都会被强制渲染到同一固定坐标(默认为 top: 0; left: 0),造成视觉上“全部堆叠”的假象。同时,counter-reset: item 若仅在顶层 <ol> 上声明,子 <ol> 不会自动继承独立计数器作用域,导致 counters(item, ".") 在所有层级复用同一计数器,进一步加剧显示错乱。
✅ 正确做法是:移除 position: fixed,仅保留在容器(如 #toccontain)上;将 counter-reset 移至每个 <ol>,确保嵌套计数独立;使用标准块级布局保证自然流式排列。
以下是修正后的关键 CSS:
立即学习“前端免费学习笔记(深入)”;
#toccontain {
position: fixed;
left: 0;
top: 0;
width: 300px;
padding: 1rem;
background: #fff;
box-shadow: 0 0 8px rgba(0,0,0,0.1);
overflow-y: auto;
max-height: 100vh;
}
/* ✅ 修正:ol 不再 fixed,恢复正常文档流 */
ol {
counter-reset: item; /* ✅ 每个 ol 都需独立重置计数器 */
list-style: none; /* ✅ 禁用原生序号,改用伪元素生成 */
padding-left: 0;
margin: 0;
}
ol li {
margin: 4px 0; /* ✅ 控制垂直间距,避免紧贴 */
line-height: 1.5;
}
ol li:before {
content: counters(item, ".") " ";
counter-increment: item;
font-weight: bold;
margin-right: 0.5em;
}
/* ✅ 子 ol 缩进以体现层级关系 */
ol ol {
margin-left: 1.5em;
}
ol ol ol {
margin-left: 1.5em;
}
a {
color: #000;
text-decoration: none;
display: inline-block; /* ✅ 防止换行截断 */
padding: 2px 4px;
}
a:hover,
a.active {
color: green;
}⚠️ 注意事项:
- 切勿对 <ol> 或 <li> 设置 position: fixed/absolute —— 这会破坏嵌套列表的自然层级和流式布局;
- counter-reset 必须作用于每个 <ol> 元素(包括嵌套的),否则 counters() 无法正确生成多级编号(如 1.1.2);
- 使用 margin-left 而非 padding-left 控制缩进更符合语义,避免影响点击区域;
- 为 #toccontain 添加 overflow-y: auto 和 max-height 可防止长目录溢出视口;
- 原 JS 代码(IntersectionObserver 高亮逻辑)完全无需修改——它只依赖 DOM 结构和 class 操作,与 CSS 布局无关。
最终效果:列表项按 HTML 嵌套层级自然垂直排列,编号自动生成(1 → 1.1 → 1.1.1),滚动高亮功能保持完美运行。修复本质是回归 CSS 布局基本原则:让元素在文档流中各司其职,而非用定位强行“钉住”破坏结构。


















