counter-reset与counter-increment必须成对使用:前者在父容器初始化计数器(如counter-reset: section),后者在子元素触发递增(如counter-increment: section),再通过::before+content: counter(section)显示编号;计数器名区分大小写,嵌套需用counters()并确保作用域正确。

counter-reset 和 counter-increment 怎么配对用?
自动编号的核心是两个声明:counter-reset 定义计数器起点,counter-increment 控制每次触发时的累加逻辑。它们必须配合 ::before 或 ::after 伪元素 + content: counter() 才能显示数字。
-
counter-reset通常写在父容器上(比如ol、section或自定义div.list),值为计数器名,可选初始值(默认 0) -
counter-increment写在要编号的子元素上(如h2、li、.item),每次匹配到该元素就执行一次累加 - 同一作用域内可定义多个计数器,用空格分隔:
counter-reset: section chapter
常见错误:把 counter-reset 写在要编号的元素自身上——这会导致每次渲染都重置,编号永远是 1。
如何实现多级嵌套编号(如 1.1、1.1.1)?
靠多个计数器嵌套 + counter() 的第二个参数控制层级。外层计数器负责主序号,内层在每次进入子结构时重置并递增。
- 父级用
counter-reset: section,子项用counter-increment: section - 子容器(如
.subsection)同时设counter-reset: subsection和counter-increment: section - 编号显示时用
counter(section)和counter(subsection)拼接,或直接用counters()函数:content: counters(section, ".")
注意:counters() 的第二个参数必须是字符串字面量(如 "."),不能是变量或 CSS 自定义属性;它只对当前计数器及其所有祖先生效,不支持跳级引用。
为什么 content: counter(x) 不生效?
最常踩的坑是漏掉 content 声明,或写在非伪元素上。
-
counter()只能在::before或::after的content值中使用,不能用于text-content、attr()或其他属性 - 如果父容器没设
counter-reset,且子元素又没继承到已定义的计数器,counter(x)返回空字符串(不是 0) - 计数器名区分大小写:
counter(Section)≠counter(section) - 避免在
display: none元素上设置counter-increment—— 它仍会累加,但视觉不可见,容易导致后续编号错位
调试建议:临时给伪元素加 border: 1px solid red,确认是否渲染;用浏览器开发者工具检查 computed 样式里是否有 content 值。
和 HTML <ol></ol> 相比,CSS counter 有什么实际优势?
<ol></ol> 语义清晰、开箱即用,但灵活性差;CSS counter 的价值在于脱离 HTML 结构约束。
- 可对任意元素编号(
div、article、h3),不依赖列表语义 - 支持条件编号:用
:not(.skip)排除某些元素,或结合@media在打印时启用编号而屏幕隐藏 - 能组合文本与计数器:
content: "第 " counter(section) " 节" - 无 DOM 层级污染:不需要额外包裹
<li>或<span></span>
性能提示:大量嵌套层级(>5 层)+ 频繁 DOM 变动时,counters() 可能引发重排开销;此时建议用 JS 控制或降级为静态编号。
真正难的是跨组件复用计数器名时的作用域管理——CSS 没有模块化命名空间,counter-reset: item 在多个独立卡片里会互相干扰。要么靠 BEM 类名隔离,要么干脆交给 JS 处理。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











