counter-reset必须写在父容器上,因为它是定义计数器起始值和作用域的声明,只对后续子元素生效;写在子元素(如li)上会导致每个子元素都重置自身,编号全为1。

CSS Counter 不能替代 <ol></ol> 的语义化编号,但能灵活控制多级嵌套、跳号、自定义前缀等场景——前提是理解它的两个核心函数 counter-reset 和 counter-increment 的作用边界。
为什么 counter-reset 必须写在父容器上?
Counter 是 CSS 中的“作用域变量”,counter-reset 定义计数器的起始值和作用范围。它只对**后续的子元素生效**,且重置发生在渲染时的布局流中。
- 写在
<li>上:每个<li>都重置自己,结果全是 1 - 写在
<ul></ul>或<ol></ol>上:所有直接子<li>共享同一个计数器实例 - 嵌套时需在每层容器(如子
<ul></ul>)上单独写counter-reset,否则子项会沿用父级计数器
示例:
ol {
counter-reset: section;
}
li {
counter-increment: section;
}
li::before {
content: counters(section, ".") ". ";
}
counters() 和 counter() 的区别在哪?
counter() 只取当前作用域的计数值;counters() 会把嵌套层级的计数器拼成带分隔符的字符串,专为多级列表设计。
-
counter(section)→ 输出 "1", "2", "3" -
counters(section, ".")→ 在嵌套<li>内输出 "1.1", "1.2", "2.1" -
counters(section, "-")→ 输出 "1-1", "1-2" - 第二个参数必须是字符串字面量,不能是变量或 CSS 自定义属性
如何跳过编号或手动指定某项序号?
CSS Counter 本身不支持“跳号”或“设为特定值”,但可通过组合 counter-increment 的增量值间接实现。
- 想让某项显示为 5:前一项的
counter-increment: section 4(即加 4) - 想跳过 3:在第 2 项后加
counter-increment: section 2,使下一项从 4 开始 - 想重置为 0 并重新开始:在目标元素父容器上再写一次
counter-reset: section 0 - 注意:这些操作会让后续项依赖前序 DOM 顺序,DOM 移动或 JS 动态插入容易错乱
兼容性和可访问性要注意什么?
Counter 生成的内容属于 ::before/::after 伪元素,**不会被屏幕阅读器读出,也不参与 DOM 序列化**。
- 语义化编号必须用原生
<ol></ol>+<li>,CSS Counter 仅作视觉增强 - IE8+ 支持
counter(),但 IE 不支持counters()(IE9+ 才支持) - 若用 JS 获取编号(比如导出 PDF),伪元素内容无法被
textContent读取,得靠getComputedStyle(el, "::before").content解析 - 打印时部分浏览器可能不渲染伪元素内容,需额外加
@media print规则确保可见
真正麻烦的是嵌套层级深、动态增删项、还要兼顾无障碍的场景——这时候不如交还给 HTML 语义和 JS 控制,CSS Counter 更适合静态结构或视觉微调。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











