CSS计数器通过counter-reset和counter-increment实现自定义起始值与步长,需在父容器设置重置、子元素触发累加,并用::before配合content显示,同时禁用默认list-style-type。

用 counter-reset 和 counter-increment 控制序号起始与步长
浏览器默认的 <ol> 只能从 1 开始、步长为 1,想从 100 开始、每项加 5,或者跳过某些数字,必须用 CSS 计数器。核心是两步:在父容器设 counter-reset 初始化计数器,在 <li> 上用 counter-increment 触发累加。
常见错误是把 counter-reset 写在 <li> 上——这会让每一项都重置,结果全是 “1”。正确做法是写在 <ol> 或包裹容器上。
-
counter-reset: my-counter 100;表示新建名为my-counter的计数器,初始值为 100 -
counter-increment: my-counter 5;表示每次匹配到该规则时,计数器加 5 - 序号显示靠
content: counter(my-counter);,必须配合::before伪元素
用 list-style-type: none + ::before 完全接管序号样式
一旦用了自定义计数器,就得关掉默认序号,否则会叠在一起。关键是把 <ol> 或 <ul> 的 list-style-type 设为 none,再用 ::before 插入内容。
容易忽略的是:如果列表项有 display: flex 或 display: grid,::before 可能不占布局空间,导致序号和文字错位。稳妥做法是给 <li> 设 position: relative,再让 ::before 绝对定位或用 margin-right 推开正文。
立即学习“前端免费学习笔记(深入)”;
示例:
ol.custom {
list-style-type: none;
padding-left: 0;
}
ol.custom li {
position: relative;
padding-left: 3em;
}
ol.custom li::before {
content: counter(my-counter) ".";
counter-increment: my-counter 2;
position: absolute;
left: 0;
}
多级嵌套列表中避免计数器污染
如果页面里有多个自定义编号列表,比如“章节 2.3.1”这种结构,不能共用同一个计数器名,否则内层会干扰外层。每个层级应使用独立计数器名,并在父级重置子级计数器。
典型场景:主章节用 chapter,小节用 section,子项用 subsection。外层 <ol class="chapter"> 里每个 <li> 包含一个 <ol class="section">,就要在 .chapter li 上同时做 counter-increment: chapter 和 counter-reset: section。
- 不重置子计数器 → 子列表序号会接着上一个子列表继续累加
- 用
counter(chapter, decimal)可指定格式,但decimal是默认值,通常不用显式写 - 中文序号(一、二、三)用
counter(chapter, cjk-ideographic),注意不是所有浏览器都支持cjk-ideographic
IE 不支持 counter() 时的降级方案
IE11 及更早版本不支持 counter() 函数,但支持 list-style-type 的部分扩展值(如 hebrew、georgian)。如果必须兼容 IE,只能放弃 CSS 计数器,改用内联 HTML 序号或 JS 动态插入。
纯 CSS 方案下,最简降级是保留 <ol start="10"> 和 value 属性——它们在 IE 中有效,但无法实现非线性步长或复杂格式。
例如:<li value="105">第一项</li> 在 IE 和现代浏览器中都显示 “105.”,但后续项仍按默认步长 +1,不能自动算出 110、115。
真正需要动态逻辑(比如根据数据源生成序号)时,CSS 就不够用了,得切到 JS 渲染——这时候序号本质是数据的一部分,不该由样式层承担。



















