必须先用counter-reset初始化计数器,否则counter()返回空字符串;常见错误是只写counter()而漏掉父容器的counter-reset声明,或重置位置错误导致作用域不覆盖目标元素。

为什么 ::before 里用 counter() 没反应?
直接写 content: counter(my-counter); 却不显示编号,大概率是漏了初始化——counter 不是声明即生效的变量,它必须先被 counter-reset 创建(或重置),否则 counter() 返回空字符串。
常见错误场景:只在 ::before 里调用 counter(),但父容器或祖先元素没设 counter-reset;或者重置写在了错误的选择器上(比如写在 li::before 里,而不是 ol 或 ul 容器上)。
-
counter-reset必须作用于「包含所有要编号子元素」的父级容器(如ol、.list) - 若想从 2 开始编号,写成
counter-reset: my-counter 1;(起始值比第一个编号小 1) - 多个独立编号序列需用不同名称,例如
counter-reset: section 0; counter-reset: figure 0;
如何给非 ol/ul 元素实现类似有序列表的自动编号?
比如一组 div.card 或 section 需要「1. 标题」「2. 标题」这样的前缀,就得靠 counter-reset + counter-increment + ::before 三者配合。
关键点在于:counter-increment 要写在「每个要编号的项」上(不是容器),而 counter-reset 写在容器上。顺序不能颠倒。
section {
counter-increment: section;
}
section::before {
content: counter(section) ". ";
font-weight: bold;
}
.main-sections {
counter-reset: section;
}
注意:counter-increment 默认每次加 1,也可写成 counter-increment: section 2; 实现隔数编号。
counter() 和 counters() 什么时候该用哪个?
counter(name) 用于单层编号(如 1, 2, 3);counters(name, separator) 用于嵌套结构(如 1.1, 1.2, 2.1),它会自动拼接所有上级同名计数器。
使用 counters() 时,必须确保每一层都设置了 counter-increment,且父级也用了 counter-reset —— 否则中间某层断掉,后续层级就全乱了。
- 多级标题编号推荐:
h1 { counter-reset: section; },h2 { counter-reset: subsection; counter-increment: section; },h2::before { content: counters(section, ".") " "; } -
counters()的separator必须是字符串字面量,如"."或">",不能是变量或 CSS 自定义属性 - IE 仅支持
counter(),不支持counters();现代浏览器两者都支持
容易被忽略的兼容性与样式限制
content 只在 ::before 和 ::after 伪元素中合法,不能用在普通元素上;而且它的值只能是字符串、counter()、counters()、attr() 或它们的组合,不能是数字、CSS 变量(var(--x))或表达式。
- 无法用
counter()做条件判断(比如“如果编号 > 5 就换颜色”),CSS 没有逻辑分支 - 计数器值无法通过 JS 直接读取(
getComputedStyle(el).content返回的是字符串,不是原始数值) - 若元素被
display: none,它仍会触发counter-increment(除非该元素本身被移出渲染树,比如visibility: hidden不影响计数)
真正麻烦的地方在于:计数器作用域是隐式的,依赖 DOM 层级和 CSS 选择器匹配顺序,一旦结构嵌套变深或动态增删节点,编号很容易错位,调试时得一层层检查 counter-reset 和 counter-increment 是否落在了预期元素上。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











