不能直接用的type和start实现多级连续编号,因其嵌套时会重置子列表计数且无法跨层级串联;必须用counter-reset/counter-increment定义多级独立计数器,并通过counters(section, ".")生成如“2.3.1”格式,同时禁用原生编号以避免叠加。

为什么不能直接用 <ol></ol> 的 type 和 start 实现多级连续编号
浏览器原生 <ol></ol> 在嵌套时会重置子列表计数(比如外层是 1、2,内层又从 1 开始),且无法跨层级串联编号(如 2.3.1)。counter() 是唯一能手动控制层级递增与格式拼接的方案。
关键点在于:必须关闭原生编号(list-style: none),改用 ::before + counter() 生成内容,否则原生和自定义会叠加显示。
如何用 counter-reset 和 counter-increment 定义多级计数器
每个层级需独立命名计数器(如 section、subsection),并在对应元素上触发递增。父级 <ol></ol> 重置所有下级计数器,子级 <ol></ol> 只重置自己的下级。
- 顶层
<ol class="toc"></ol>设置counter-reset: section - 每项
<li>内部设置counter-increment: section - 子
<ol></ol>设置counter-reset: subsection,其<li>增subsection - 若需三级,再加
subsubsection,依此类推
怎么用 counter() 拼出 2.3.1 这样的嵌套格式
counter() 函数本身只返回单个计数器值,拼接靠多个 counter() 并列 + 字符串分隔符。注意:分隔符(如 ".")必须写在 content 中,不能靠空格或换行。
立即学习“前端免费学习笔记(深入)”;
li::before {
content: counter(section) "." counter(subsection) "." counter(subsubsection);
}
但这样会导致未展开层级显示 1.. 或 1.2. —— 解决办法是:只对有子列表的 <li> 应用更长的 content,或统一用 counters() 函数(更稳妥):
li::before {
content: counters(section, ".") " ";
}
counters() 自动按嵌套深度提取对应层级计数器,无需手动命名每一级,也避免空段问题。
常见错误:编号错乱、重复、跳号的实际原因
多数问题出在计数器作用域和重置时机不对:
-
counter-reset写在<li>上而非<ol></ol>→ 子列表没被重置,数字累加 - 忘记给最外层
<ol></ol>设counter-reset→ 所有counter()返回 0 - 用
counter(section)但没在任何地方counter-increment: section→ 始终为 0 -
<li>包含多个块级元素,::before被挤到换行位置 → 加display: inline-block或调整float
真正麻烦的是动态插入 DOM 后计数器不自动更新 —— counter() 是纯 CSS 渲染时计算的,JS 新增 <li> 后必须确保它也带正确的 counter-increment,否则编号断掉。



















