CSS counter() 函数(一文讲透)

什么是 CSS counter() 函数?初学者也能看懂的入门指南

在日常的网页开发中,我们常常需要为页面中的标题、列表项或章节编号自动添加序号。虽然用 HTML 的 <ol> 标签可以实现简单的有序列表,但当需求变得复杂,比如嵌套章节、自定义样式、跨元素编号时,传统的方案就显得力不从心了。

这时候,CSS 提供了一个强大而低调的工具——counter() 函数。它允许你通过 CSS 实现自动编号,而无需在 HTML 中手动写入数字。这不仅让代码更干净,也极大提升了维护性。

想象一下,你正在写一本电子书,每一章都有自己的编号,每一节也有子编号。如果每改一次结构,就要手动调整所有编号,那简直是一场灾难。而 counter() 函数就像一个自动记分员,你只需要告诉它“从第 1 章开始”,它就会自动为每一节生成正确的编号。


如何使用 counter() 函数?从零开始的实践

要使用 counter() 函数,你需要先在 CSS 中定义一个“计数器”,然后通过 counter() 函数在伪元素(如 ::before::after)中显示它。

定义计数器:counter-reset

首先,使用 counter-reset 属性来创建一个计数器。它通常作用于父元素,表示从哪个数值开始计数。

/* 定义一个名为 chapter 的计数器,初始值为 0 */
.chapter-container {
  counter-reset: chapter;
}

这里的 chapter 是计数器的名字,你可以随便取,比如 sectionstep 都可以。counter-reset 的值默认为 0,你也可以指定其他初始值,例如:

.chapter-container {
  counter-reset: chapter 1; /* 从 1 开始 */
}

增加计数器:counter-increment

接下来,让每个子元素在渲染时“增加”计数器。使用 counter-increment 属性。

/* 每个 .chapter 元素都让 chapter 计数器加 1 */
.chapter {
  counter-increment: chapter;
}

注意:counter-increment 只对设置了 counter-reset 的父元素有效。如果父元素没有定义计数器,子元素的 counter-increment 不会生效。

显示计数器:使用 counter() 函数

最后,使用 content 属性配合 counter() 函数在伪元素中显示计数。

.chapter::before {
  content: counter(chapter) "、"; /* 显示编号,后跟顿号 */
  font-weight: bold;
  color: #333;
}

完整的 HTML 示例:

<div class="chapter-container">
  <div class="chapter">第一章:基础概念</div>
  <div class="chapter">第二章:布局技巧</div>
  <div class="chapter">第三章:响应式设计</div>
</div>

最终效果: 1、第一章:基础概念
2、第二章:布局技巧
3、第三章:响应式设计

💡 小贴士:counter() 函数只能用于 content 属性中,且必须结合伪元素使用。


嵌套计数器:实现多级编号系统

很多文档系统都支持多级编号,比如 1.1、1.2、2.1、2.2。这在 counter() 函数中实现起来非常简单。

每一级都定义自己的计数器

/* 第一级:章节 */
.chapter {
  counter-reset: section; /* 每个章节重置 section 计数器 */
  counter-increment: chapter;
}

/* 第二级:节 */
.section {
  counter-increment: section;
}

使用嵌套的 counter() 函数

.chapter::before {
  content: counter(chapter) "、";
  font-weight: bold;
}

.section::before {
  content: counter(chapter) "." counter(section) "、";
  font-size: 0.9em;
  color: #555;
}

HTML 示例:

<div class="chapter">
  <div class="section">第一节:什么是 CSS</div>
  <div class="section">第二节:选择器语法</div>
  <div class="section">第三节:盒模型</div>
</div>

效果: 1、第一节:什么是 CSS
1.1、第二节:选择器语法
1.2、第三节:盒模型

✅ 关键点:counter() 函数会自动识别嵌套结构中的父级计数器,实现层级编号。


自定义编号格式:从数字到字母、罗马数字

counter() 函数支持多种编号格式,通过 counter() 的第二个参数控制。

常见的格式类型

格式类型 示例 说明
decimal 1, 2, 3 十进制数字(默认)
lower-alpha a, b, c 小写字母
upper-alpha A, B, C 大写字母
lower-roman i, ii, iii 小写罗马数字
upper-roman I, II, III 大写罗马数字
decimal-leading-zero 01, 02, 03 前导零的十进制

实际应用示例

/* 使用小写字母编号 */
.letter-list li::before {
  content: counter(item, lower-alpha) ") ";
  color: #007acc;
}

/* 使用罗马数字 */
.roman-list li::before {
  content: counter(item, upper-roman) "、";
  font-style: italic;
}

/* 使用带前导零的编号 */
.zeropadded li::before {
  content: counter(item, decimal-leading-zero) "、";
}

HTML:

<ul class="letter-list">
  <li>第一项</li>
  <li>第二项</li>
  <li>第三项</li>
</ul>

<ul class="roman-list">
  <li>第一项</li>
  <li>第二项</li>
  <li>第三项</li>
</ul>

<ul class="zeropadded">
  <li>第一项</li>
  <li>第二项</li>
  <li>第三项</li>
</ul>

效果: a) 第一项
b) 第二项
c) 第三项

I、第一项
II、第二项
III、第三项

01、第一项
02、第二项
03、第三项


常见问题与注意事项

1. 计数器不会跨父级生效

/* 错误示例:没有定义 counter-reset,不会生效 */
.no-reset::before {
  content: counter(my-counter); /* 无效! */
}

必须先在父级定义 counter-reset,子元素才能使用。

2. counter() 函数不能在非 content 属性中使用

/* 错误用法 */
.element {
  width: counter(chapter); /* ❌ 不合法 */
}

只有 content 属性支持 counter()

3. 重置计数器的位置很重要

.chapter-container {
  counter-reset: chapter; /* ✅ 正确:在父级定义 */
}

.chapter {
  counter-increment: chapter;
}

如果 counter-reset 写在子元素上,会导致计数器无法正确继承。


高级技巧:与 CSS 变量结合使用

虽然 counter() 本身不支持变量,但你可以通过 CSS 自定义属性(变量)来控制计数器的初始值,实现动态控制。

.article {
  --start-number: 5;
  counter-reset: section var(--start-number); /* 使用变量作为初始值 */
  counter-increment: chapter;
}

.article::before {
  content: counter(chapter) "、";
}

这在动态生成内容时非常有用,比如从后端传入起始编号。


总结:为什么你应该掌握 CSS counter() 函数?

counter() 函数是 CSS 中一个被低估但极其实用的功能。它不仅能让你摆脱手动编号的繁琐,还能轻松实现复杂的多级编号系统,比如书籍目录、技术文档、教程结构等。

相比用 JavaScript 动态生成编号,counter() 纯 CSS 实现更高效、更易维护,且对 SEO 友好。它不需要额外的脚本,浏览器原生支持,兼容性良好(现代浏览器全部支持)。

更重要的是,它让你的 HTML 更语义化。你不再需要在每个标题里写 1.2.,而是让 CSS 自动完成编号任务,真正做到了“内容与表现分离”。

无论你是初学者还是中级开发者,掌握 counter() 函数,都能让你在编写结构化文档、教程或后台管理系统时,事半功倍。

如果你正在为某个页面设计自动编号系统,不妨试试 counter() 函数。它可能就是你一直在找的“隐藏利器”。