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

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











