用CSS计数器实现多级编号需配合正确HTML结构:外层ol的start仅影响本层,子项编号依赖counters(list-item,".")函数提取嵌套层级值,且子ol必须直接嵌在父li内,同时清除list-style并用::before插入content。

直接用 <ol> 套 <li> 就能做出安装配置向导,但真要让步骤编号自动带层级(比如“2.1”“2.3.2”)、支持自定义起始值、不被浏览器解析错乱,关键不在标签堆砌,而在 CSS 计数器和 HTML 结构的配合。
为什么 start 属性单独用不了多级编号
很多人试过给外层 <ol start="2">,再嵌套一个 <ol>,结果子项还是从 1 开始显示——因为 start 只影响当前列表的初始计数值,不传递给内层。浏览器不会自动把“2”拼到子项前面。真正起作用的是内置的 list-item 计数器,它天然按嵌套层级累积,但默认只在 list-style-type 中体现一级数字。
所以必须用 CSS 的 counters() 函数显式提取并拼接各级 list-item 值:
-
counters(list-item, ".")→ 输出 “2.1”、“2.2” 这类带点分隔的完整路径 - 不能写成
counter(list-item)(单级)或counters(my-counter, ".")(手动声明的 counter 不继承start) - 必须确保 HTML 中子
<ol>是直接嵌在父<li>内部,不能被<p>或<div>包裹,否则计数链断裂
list-style-type 和 list-style 别混用
想让编号是 “2.1” 而不是 “1.”,就不能依赖 <ol type="1"> 这种老式属性——它只控制单级样式,且和 CSS 计数器冲突。正确做法是彻底清掉默认样式:
立即学习“前端免费学习笔记(深入)”;
- 给所有
<ol>加list-style: none(或list-style-type: none) - 只用
::before+content: counters(list-item, ".")插入编号 - 如果还写了
list-style-type: decimal,部分浏览器会同时渲染两套编号,造成重叠
常见结构错误导致编号跳变或丢失
安装向导这类线性流程最怕编号错乱。以下结构问题实际发生率极高:
- 漏写
</li>:写成<li>下载安装包<ol><li>双击 exe</li></ol>—— 浏览器会把内层<ol>当作文本节点,counters()失效 - 在
<li>里加了<div>包裹内容:<li><div>解压文件</div><ol>...</ol></li>——<div>不是标准列表容器,打断计数上下文 - 用
display: flex包裹<ol>:flex 容器会让list-item计数器失效,编号全变成 “1.” - JS 动态插入
<li>后没触发重排:新项编号可能沿用旧值,需强制getComputedStyle(ol).counterReset或重设counter-reset
真正难的不是写出 “2.1”,而是确保每一层嵌套都落在浏览器计数器的自然路径上——start 设定外层起点,counters(list-item, ".") 沿着 DOM 树深度优先遍历提取值,中间任何结构偏移都会让后续编号脱节。动手前先检查 HTML 是否严格符合 <ol><li>...<ol><li>...</li></ol></li></ol> 这一链条。



















