⭐ 推荐:社区规则条款 V1.0

CSS计数器做自动编号。

一只冷漠的狐狸
一只冷漠的狐狸 正式会员正式会员认证极客认证极客 钻石卡会员钻石卡会员
发布于 2026-07-24 19:28 ·75 浏览 ·0 回复
内容摘要

CSS计数器通过父级counter-reset归零、子项counter-increment递增、伪元素content:counter()显示实现自动编号,支持格式参数和counters()多级嵌套,需注意display:none元素不参与计

CSS 计数器(CSS Counters)能用三行声明给任何重复元素自动编号:counter-reset 定起点、counter-increment 递增、content: counter() 显示,不写 JS、不手写数字,增删条目后编号自动重排。

三步走:reset、increment、显示

结论:CSS 计数器永远是同一个套路——父级归零、子项递增、伪元素显示,三者缺一不可。

.list { counter-reset: item; }             /* 1. 定义计数器并归零,作用域含所有后代 */
.list > li { counter-increment: item; }    /* 2. 每个子项 +1 */
.list > li::before {
  content: counter(item) ". ";             /* 3. 输出当前值 */
  color: #888;
}

三点必须记牢:

第一,counter-reset 写一次就够,写在父容器上,所有后代共享同一个计数器实例。写在每个 li 上会导致每个都是 1。想从 10 开始编号,写 counter-reset: item 9,元素递增后就是 10。

第二,content 只在 ::before、::after、::marker 里生效。把 content 写在普通元素上不会有任何效果,这是新手最常见的踩坑点。

第三,counter-increment 建议写在元素本身而不是 ::before 上,语义更清楚,也不受伪元素盒模型影响。

编号样式:罗马数字、中文、前导零都不用自己拼

结论:counter() 的第二个参数直接复用 list-style-type 那一套取值,想要什么格式改参数就行。

  • content: counter(item, upper-roman) → I. II. III.
  • content: counter(item, lower-alpha) → a. b. c.
  • content: counter(item, cjk-decimal) → 一、二、三
  • content: counter(item, decimal-leading-zero) → 01、02、03

如果这些还不够,用 @counter-style 自定义规则集,可以定义前后缀、进制、循环符号,注册后同样能传给 counter() 使用。

嵌套编号:1.1、1.2 用 counters()

结论:多级列表要用带 s 的 counters(),它会把同名计数器在各层的值拼接成一条链。

ol { counter-reset: sec; list-style: none; }
li { counter-increment: sec; }
li::before { content: counters(sec, ".") " "; }
ol ol { counter-reset: sec; }   /* 进入下一层时归零,实现 1.1 / 1.2 */

counters(sec, ".") 的第二个参数是连接符,换成 "-" 就得到 1-1、1-2 的效果。文章目录、多级大纲、章节编号都靠这个。

四个容易翻车的细节

结论:计数器好用,但有几个行为跟直觉不一样,提前知道能省一小时调试。

  1. display: none 的元素不参与计数,用它做「条件显示 + 连续编号」会断号。
  2. 计数器名区分大小写,item 和 Item 是两个互不相干的计数器。
  3. 伪元素里的编号不进剪贴板,也不会被屏幕阅读器朗读。如果编号是内容的一部分(比如「第一步:注册」),务必在 HTML 里也写出来,或补 aria-label,别让信息只活在 CSS 里。
  4. 现代浏览器已支持 counter-reset: item reversed(10) 做反向倒计数,但旧内核兼容性一般,正式项目建议先测目标环境。

什么时候该用它

结论:凡是「条目数量会变、编号要连续」的重复结构,都值得交给 CSS 计数器。

典型场景有三类:一是列表自动编号,比如答题选项、排行榜名次;二是多级目录,用 counters() 输出 2.3.1 这种层级号;三是后台渲染的表行号、论坛楼层号、问答聚合页里 FAQ 的序号——只要它们是同一个 DOM 结构循环渲染出来的,编号就不需要后端再算一遍序号字段,也不需要前端 forEach 时手动拼 index。条目被删除、排序被调整时,编号跟着 DOM 自动重排,永远不会出现断号或重号。

需要提醒的是,计数器只负责「显示层编号」,不改变 DOM 顺序,也不生成可被爬虫抓取的文本。如果你需要编号参与 SEO 或数据导出,仍要在服务端把序号落成真实文本。

一句话收束:counter-reset 起头、counter-increment 步进、content: counter() 露面,多级用 counters(),格式靠第二个参数,避开 display: none 和纯伪元素承载信息这两个坑,自动编号这件事就不用再写一行业务代码了。

本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-421.html
转载请注明出处,版权归原作者所有。

全部回复 0

还没有回复,来抢沙发~