使用 CSS 计数器
**CSS 计数器**允许您根据内容在文档中的位置调整内容的外观。例如,您可以使用计数器自动对网页上的标题进行编号,或更改有序列表的编号。
从本质上讲,计数器是由 CSS 维持的变量,其值可以通过跟踪使用次数的 CSS 规则来递增或递减。以下因素会影响元素上的计数器值
- 计数器从父元素继承或从之前的兄弟元素接收。
- 新的计数器使用
counter-reset
属性实例化。 - 计数器使用
counter-increment
属性递增。 - 计数器使用
counter-set
属性直接设置为某个值。
您可以定义您自己的命名计数器,也可以操作默认情况下为所有有序列表创建的list-item
计数器。
使用计数器
要使用计数器,它必须首先使用counter-reset
属性初始化为某个值。计数器的值可以使用counter-increment
属性增加或减少,并可以使用counter-set
属性直接设置为特定值。计数器的当前值使用counter()
或counters()
函数显示,通常在伪元素content
属性中。
计数器只能在生成盒子的元素中设置、重置或递增。例如,如果元素设置为display: none
,则该元素上的任何计数器操作都将被忽略。
计数器的属性可以使用样式包含作用于特定元素,这在contain
属性中更详细地描述。
操作计数器的值
要使用 CSS 计数器,它必须首先使用counter-reset
属性初始化为某个值。该属性也可以用于将计数器值更改为任何特定数字。
下面我们初始化一个名为section
的计数器,其默认值为 (0)。
counter-reset: section;
您还可以初始化多个计数器,可以选择为每个计数器指定一个初始值。下面我们将section
和topic
计数器初始化为默认值,并将page
计数器初始化为 3。
counter-reset: section page 3 topic;
初始化后,可以使用counter-increment
增加或减少计数器的值。例如,以下声明将在每个h3
标签上将section
计数器递增 1。
h3::before {
counter-increment: section; /* Increment the value of section counter by 1 */
}
您可以在计数器名称后指定递增或递减量。它可以是正数或负数,但如果未提供整数,则默认为1
。
除了递增或递减之外,还可以使用counter-set
属性将计数器显式设置为某个值。
.done::before {
counter-set: section 20;
}
计数器名称不能为none
、inherit
或initial
;否则声明将被忽略。
显示计数器
计数器的值可以使用 counter()
或 counters()
函数在 content
属性中显示。
例如,以下声明使用 counter()
在每个 h3
标题前添加文本 Section <number>:
,其中 <number>
是计数器的十进制值(默认显示样式)。
h3::before {
counter-increment: section; /* Increment the value of section counter by 1 */
content: "Section " counter(section) ": "; /* Display counter value in default style (decimal) */
}
当嵌套级别的编号不包括父级别的上下文时,使用 counter()
函数。例如,这里每个嵌套级别都从 1 开始。
1 One 1 Nested one 2 Nested two 2 Two 1 Nested one 2 Nested two 3 Nested three 3 Three
当嵌套级别的计数必须包含父级别的计数时,使用 counters()
函数。例如,你可以使用它来布局如下所示的章节。
1 One 1.1 Nested one 1.2 Nested two 2 Two 2.1 Nested one 2.2 Nested two 2.3 Nested three 3 Three
counter()
函数有两种形式:counter(<counter-name>)
和 counter(<counter-name>, <counter-style>)
。生成的文本是伪元素作用域内给定名称的最内层计数器的值。
counters()
函数也有两种形式:counters(<counter-name>, <separator>)
和 counters(<counter-name>, <separator>, <counter-style>)
。生成的文本是伪元素作用域内给定名称的所有计数器的值,从最外层到最内层,用指定字符串 (<separator>
) 分隔。
计数器使用指定的 <counter-style>
呈现(默认情况下为 decimal
)。你可以使用任何 list-style-type
值或你自己的 自定义样式。
反向计数器
反向计数器是指旨在倒数(递减)而不是递增的计数器。反向计数器是在 counter-reset
中命名计数器时,使用 reversed()
函数符号创建的。
反向计数器的默认初始值等于元素数量(与默认值为 0 的普通计数器不同)。这使得实现从元素数量倒数到一的计数器变得容易。
例如,要创建一个名为 section
的反向计数器,并使用默认初始值,可以使用以下语法。
counter-reset: reversed(section);
当然,你可以指定任何你喜欢的初始值。
通过为 counter-increment
指定负值来减少计数器值。
注意: 你也可以使用 counter-increment
来递减非反向计数器。使用反向计数器的主要好处是默认初始值,以及 list-item
计数器会自动递减反向计数器。
计数器继承和传播
每个元素或伪元素在该元素的作用域内都有一组计数器。集合中的初始计数器从元素的父元素和前面的兄弟元素接收。计数器值从前一个兄弟元素的最后一个后代、最后一个兄弟元素或父元素接收。
当元素声明计数器时,计数器嵌套在从父元素接收的同名计数器中。如果父元素没有同名计数器,则将计数器按原样添加到元素的计数器集中。从前一个兄弟元素接收的同名计数器将从计数器集中删除。
counter()
函数检索提供的名称的最内层计数器。而 counters()
函数检索具有给定名称的整个计数器树。
在以下示例中,我们演示了一个名为 primary
的继承计数器和一个名为 secondary
的兄弟计数器。所有 <div>
元素都使用 counters()
函数显示其计数器。请注意,所有计数器都是使用 counter-reset
属性创建的,并且没有一个计数器被递增。
<section>
counter-reset: primary 3
<div>A</div>
<div>B</div>
<div>C</div>
<div class="same-primary-name">D</div>
<span> counter-reset: primary 6</span>
<div>E</div>
<div class="new-secondary-name">F</div>
<span> counter-reset: secondary 5</span>
<div>G</div>
<div>H</div>
<div class="same-secondary-name">I </div>
<span> counter-reset: secondary 10</span>
<div>J </div>
<div>K</div>
<section></section>
</section>
/* create 'primary' counter on divs' parent */
section {
counter-reset: primary 3;
}
div::after {
content: " ('primary' counters: " counters(primary, "-", style)
", 'secondary' counters: " counters(secondary, "-", style) ")";
color: blue;
}
/* create new 'primary' counter */
.same-primary-name {
counter-reset: primary 6;
}
/* create 'secondary' counter on div 'F' */
.new-secondary-name {
counter-reset: secondary 5;
}
/* override the sibling 'secondary' counter */
.same-secondary-name {
counter-reset: secondary 10;
}
section 元素用值为 3
的 primary
计数器初始化,所有子 <div>
接收继承的 primary
计数器。元素“D”创建了一个新的 primary
(值为 6
)计数器,它嵌套在从父元素接收的计数器中,因此该元素有两个名为 primary
的计数器,值为 3
和 6
。
元素“F”首次创建 secondary
(值为 5
)计数器,并将该计数器传递给下一个兄弟元素“G”。元素“G”将计数器传递给下一个元素“H”,以此类推。接下来,元素“I”创建了一个同名 secondary
(值为 10
)的新计数器,但它丢弃了从前一个兄弟元素“H”接收的 secondary
(值为 5
)计数器,并将它自己的计数器传递给“J”。
counter-set
和 counter-reset
的区别
counter-set
属性更新现有计数器,如果不存在同名计数器,则实例化一个新计数器。counter-reset
属性始终创建新的计数器。
在以下示例中,我们有一个父列表中包含两个子列表。每个列表项都使用名为“item”的计数器编号。第一个子列表使用 counter-set
属性,第二个子列表使用 counter-reset
属性来更改“item”计数器。
<ul class="parent">
<li>A</li>
<li>B</li>
<li>
C (the counter updated using `counter-set`)
<ul class="sub-list-one">
<li>sub-A</li>
<li>sub-B</li>
</ul>
</li>
<li>D</li>
<li>
E (a new counter created using `counter-reset`)
<ul class="sub-list-two">
<li>sub-A</li>
<li>sub-B</li>
<li>sub-C</li>
</ul>
</li>
<li>F</li>
<li>G</li>
</ul>
/* create a new counter for the first time */
.parent {
counter-reset: item 0;
}
/* increment the counter on each list item */
li {
counter-increment: item;
}
/* show numbers on list items */
li::before {
content: counter(item) " ";
}
/* change the existing counter value */
.sub-list-one {
counter-set: item 10;
}
/* change the counter value */
.sub-list-two {
counter-reset: item 0;
}
请注意第一个子列表项是如何从 11
开始接收编号的,并且编号在父列表中继续。这是因为 counter-set
属性更新了在 .parent
元素上声明的同一个“item”计数器。然后请注意第二个子列表项是如何从“1”开始接收新的编号的,并且它后面的父列表项没有继续编号。这是因为 counter-reset
属性创建了一个同名的新计数器,因此父列表项继续使用旧计数器。
列表项计数器
使用 <ol>
元素创建的有序列表隐式地包含一个名为 list-item
的计数器。
与其他计数器一样,它对向上计数器的默认初始值为 0,对反向计数器为“项目数量”。与作者创建的计数器不同,list-item
自动根据计数器是否反向,对每个列表元素递增或递减 1。
list-item
计数器可用于使用 CSS 操作有序列表的默认行为。例如,你可以更改默认初始值,或使用 counter-increment
来更改列表项递增或递减的方式。
示例
基本示例
此示例在每个标题的开头添加“Section [计数器的值]:”。
CSS
body {
counter-reset: section; /* Set a counter named 'section', and its initial value is 0. */
}
h3::before {
counter-increment: section; /* Increment the value of section counter by 1 */
content: "Section " counter(section) ": "; /* Display the word 'Section ', the value of
section counter, and a colon before the content
of each h3 */
}
HTML
<h3>Introduction</h3>
<h3>Body</h3>
<h3>Conclusion</h3>
结果
基本示例:反向计数器
此示例与上面的示例相同,但使用的是反向计数器。如果你的浏览器支持 reversed()
函数符号,则结果将如下所示。
CSS
body {
counter-reset: reversed(
section
); /* Set a counter named 'section', and its initial value is 0. */
}
h3::before {
counter-increment: section -1; /* Decrement the value of section counter by 1 */
content: "Section " counter(section) ": "; /* Display the word 'Section ', the value of
section counter, and a colon before the content
of each h3 */
}
HTML
<h3>Introduction</h3>
<h3>Body</h3>
<h3>Conclusion</h3>
结果
更复杂的示例
计数器不必每次递增时都显示。此示例统计所有链接,只有在链接没有文本时才显示计数器,作为一种方便的替代方案。
CSS
:root {
counter-reset: link;
}
a[href] {
counter-increment: link;
}
a[href]:empty::after {
content: "[" counter(link) "]";
}
HTML
<p>See <a href="https://www.mozilla.org/"></a></p>
<p>Do not forget to <a href="contact-me.html">leave a message</a>!</p>
<p>See also <a href="https://mdn.org.cn/"></a></p>
结果
嵌套计数器示例
CSS 计数器对于制作带轮廓的列表特别有用,因为在子元素中会自动创建一个新的计数器实例。使用 counters()
函数,可以在不同级别的嵌套计数器之间插入分隔文本。
CSS
ol {
counter-reset: section; /* Creates a new instance of the
section counter with each ol
element */
list-style-type: none;
}
li::before {
counter-increment: section; /* Increments only this instance
of the section counter */
content: counters(section, ".") " "; /* Combines the values of all instances
of the section counter, separated
by a period */
}
HTML
<ol>
<li>item</li> <!-- 1 -->
<li>item <!-- 2 -->
<ol>
<li>item</li> <!-- 2.1 -->
<li>item</li> <!-- 2.2 -->
<li>item <!-- 2.3 -->
<ol>
<li>item</li> <!-- 2.3.1 -->
<li>item</li> <!-- 2.3.2 -->
</ol>
<ol>
<li>item</li> <!-- 2.3.1 -->
<li>item</li> <!-- 2.3.2 -->
<li>item</li> <!-- 2.3.3 -->
</ol>
</li>
<li>item</li> <!-- 2.4 -->
</ol>
</li>
<li>item</li> <!-- 3 -->
<li>item</li> <!-- 4 -->
</ol>
<ol>
<li>item</li> <!-- 1 -->
<li>item</li> <!-- 2 -->
</ol>
结果
规范
规范 |
---|
CSS 列表和计数器模块级别 3 # 自动编号 |