你可能不知道的 CSS 計(jì)數(shù)器

前言
CSS 里面的偽元素其實(shí)是非常好用的,但是經(jīng)常容易被大家忽略,偽元素里面常用到的 content 屬性,可能現(xiàn)在很多人僅僅以為 content 屬性的值只支持字符串,除了字符串外常用到的還有 uri、counter ,今天所要介紹的就是 conter(計(jì)數(shù)器)。
先看如下的例子:

<div>
<h3>桃翁h3>
<h3>介紹h3>
<h3>css 計(jì)數(shù)器h3>
div>
根據(jù)如上的 HTML 你是否有辦法不通過 JavaScript ,僅僅用 CSS 在 title 前面增加 Title number: 呢?
CSS 計(jì)數(shù)器基本概念
如果僅僅增加一個(gè) Title,大家都知道通過偽元素(:before 或者:after),設(shè)置 content 為 Title,但是如何自動根據(jù) h3 出現(xiàn)的順序來展示自動編號可能很多人就不知道了。
自動編號在 CSS 2.1 中是通過兩個(gè)屬性控制的,'counter-increment'[1]和'counter-reset'[2]。通過這些屬性定義的計(jì)數(shù)器用于'content’[3]屬性的 counter() 和 counters() 函數(shù)
初始化計(jì)數(shù)器
在使用計(jì)數(shù)器的時(shí)候需要先初始化這個(gè)計(jì)數(shù)器,并且設(shè)置一個(gè)計(jì)數(shù)器的名字(變量)。下面是例子,title 就是名字,conter-reset 就是用來初始化的,這個(gè)屬性是必須設(shè)置的,否則沒辦法用計(jì)數(shù)器。
'counter-reset'[4]屬性也含有一列一個(gè)或多個(gè)計(jì)數(shù)器,每個(gè)后面可以跟一個(gè)可選的整數(shù)。該整數(shù)給定了每次出現(xiàn)該元素時(shí)給計(jì)數(shù)器設(shè)置的值,默認(rèn)為 0
counter-reset: 計(jì)數(shù)器名稱[, 默認(rèn)值number]; /* 重置計(jì)數(shù)器成0 */
計(jì)數(shù)器自增
有了一個(gè)計(jì)數(shù)器的變量后,然后可以讓這個(gè)變量進(jìn)行自增:
'counter-increment'[5]屬性接受一個(gè)或多個(gè)計(jì)數(shù)器名(標(biāo)識符),每個(gè)后面都可以跟一個(gè)可選的整數(shù)。這個(gè)整數(shù)表示每次出現(xiàn)該元素時(shí)計(jì)數(shù)器遞增幾。默認(rèn)增量是 1,可以接受 0 和負(fù)數(shù)
counter-increment: 計(jì)數(shù)器名稱[, 增量]; /* 增加計(jì)數(shù)器值 */
顯示計(jì)數(shù)器
最后就是現(xiàn)實(shí)計(jì)數(shù)器的值,獲取計(jì)數(shù)器的值有兩個(gè)函數(shù):counter() 和 counters() ,如上面的例子:
content: counter(計(jì)數(shù)器名稱[, 顯示的風(fēng)格]) /* 顯示計(jì)數(shù)器 */
或者
counters(計(jì)數(shù)器名稱, 嵌套時(shí)拼接字符串[, 可選的顯示風(fēng)格])
基本使用
學(xué)完了基本概念,然后就可以解決上面的問題了。按照步驟來,三步:
- 初始化計(jì)時(shí)器
div {
counter-reset: title; /* 重置計(jì)數(shù)器成0 */
}
- 計(jì)數(shù)器自增
h3:before {
counter-increment: title; /* 增加計(jì)數(shù)器值 */
}
- 顯示計(jì)數(shù)器
h3:before {
content: "Title " counter(title) ": "; /* 顯示計(jì)數(shù)器 */
}
合起來的解決方案如下:
div {
counter-reset: title; /* 重置計(jì)數(shù)器成0 */
}
h3:before {
counter-increment: title; /* 增加計(jì)數(shù)器值 */
content: "Title " counter(title) ": "; /* 顯示計(jì)數(shù)器 */
}
高級用法
嵌套計(jì)數(shù)器與作用域
計(jì)數(shù)器是“自嵌套的(self-nesting)”,如果重置一個(gè)位于后代元素或者偽元素中的計(jì)數(shù)器,會自動創(chuàng)建一個(gè)新的計(jì)數(shù)器實(shí)例。這對 HTML 中的列表之類的場景來說很重要,這種場景下,元素自身可以嵌套任意深度,不用為每一層定義唯一命名的計(jì)數(shù)器
計(jì)數(shù)器的作用域從文檔中具有'counter-reset'[6]該計(jì)數(shù)器的第一個(gè)元素開始,包括該元素的后代、后續(xù)兄弟及其后代。
官方套話比較難懂,用大白話說就是設(shè)置了 counter-reset ,那么這個(gè)元素的的子元素都屬于這個(gè)作用域下。
想要完全理解作用域,就得把下面這個(gè) 圖看懂:

上面的這個(gè) HTML 代碼,再加上這段 CSS 代碼:
OL { counter-reset: item }
LI { display: block }
LI:before {
counter-increment: item
}
OL 將會創(chuàng)建一個(gè)計(jì)數(shù)器,并且 OL 的所有子級將引用該計(jì)數(shù)器,如果我們用 item[n]表示"item"計(jì)數(shù)器的第 n 個(gè)實(shí)例,用"{"和"}"表示一個(gè)作用域的開始和結(jié)束,那么上面 HTML 片段將使用標(biāo)注的計(jì)數(shù)器。
注意看 2.3.1 的兩個(gè)元素,由于他們都在 2.3 下面,有兩個(gè)同名的計(jì)數(shù)器,那么這兩個(gè)同名計(jì)數(shù)器會分別創(chuàng)建實(shí)例,所有會得到兩個(gè) 2.3.1。
如果懂了作用域的關(guān)系,接下來就可以通過 counter() 或者 counters() 函數(shù)進(jìn)行展示。
counter
Counter 顯示代碼如下:
OL { counter-reset: item }
LI { display: block }
LI:before {
content: counter(item) ". ";
counter-increment: item
}
效果如下:

可以看到 counter 只會顯示當(dāng)前作用域下計(jì)數(shù)器的值,如果要生成嵌套作用域的計(jì)數(shù)器就得用 counters 函數(shù)。
counters
OL { counter-reset: item }
LI { display: block }
LI:before {
content: counters(item, '.') " ";
counter-increment: item;
}

更換格式
在顯示計(jì)數(shù)器部分 counter 和 counters 都有一個(gè)可選參數(shù),顯示風(fēng)格,這個(gè)顯示風(fēng)格跟 list-style-type[7] 是一樣的,比如我們將文章開頭的例子拿來舉例,默認(rèn)是 decimal 風(fēng)格,比如換成字母(type 是 lower-latin)形式,css 如下:
div {
counter-reset: title; /* 重置計(jì)數(shù)器成0 */
}
h3:before {
counter-increment: title; /* 增加計(jì)數(shù)器值 */
content: "Title " counter(title, lower-latin) ": "; /* 顯示計(jì)數(shù)器 */
}
效果如下,list-style-type 有很多種,甚至還有中文(list-style-type 是 cjk-ideographic)的。

自定義起始值
起始值訂為 5
div {
counter-reset: title 5; /*起始值訂為 5 */
}
h3:before {
counter-increment: title;
content: "Title " counter(title) ": ";
}

自定義每次遞增的值
每次遞增的值為 2
div {
counter-reset: title 5;
}
h3:before {
counter-increment: title 2; /* 每次遞增的值為 2 */
content: "Title " counter(title) ": ";
}

使用場景
場景 1:嵌套列表
比如要生成一個(gè)文章的大綱:

場景 2:計(jì)算已經(jīng)勾選的復(fù)選框
使用輸入框的:checked 偽類,我們可以檢查復(fù)選框是否被選中,選中的話,我們計(jì)數(shù)器的數(shù)值就會增加。
下面的這個(gè) 2 種菜系直接就是可以通過計(jì)數(shù)器來實(shí)現(xiàn)的,不需要使用 js

場景 3:自動追蹤文檔條目
當(dāng)你需要處理一些重復(fù)元素的時(shí)候,并且你同樣想統(tǒng)計(jì)他們的數(shù)量,那么這個(gè)方案會很好用。

參考文章
- css 計(jì)數(shù)器詳解[8]
參考資料
[1]'counter-increment': http://www.ayqy.net/doc/css2-1/generate.html#propdef-counter-increment
[2]'counter-reset': http://www.ayqy.net/doc/css2-1/generate.html#propdef-counter-reset
[3]'content’: http://www.ayqy.net/doc/css2-1/generate.html#propdef-content
[4]'counter-reset': http://www.ayqy.net/doc/css2-1/generate.html#propdef-counter-reset
[5]'counter-increment': http://www.ayqy.net/doc/css2-1/generate.html#propdef-counter-increment
[6]'counter-reset': http://www.ayqy.net/doc/css2-1/generate.html#propdef-counter-reset
[7]list-style-type: https://www.w3school.com.cn/cssref/pr_list-style-type.asp
[8]css計(jì)數(shù)器詳解: https://www.cnblogs.com/liuxianan/p/css-counters.html
推薦閱讀
我的公眾號能帶來什么價(jià)值?(文末有送書規(guī)則,一定要看)每個(gè)前端工程師都應(yīng)該了解的圖片知識(長文建議收藏)
為什么現(xiàn)在面試總是面試造火箭?
「一個(gè)有溫度的前端號」
長按識別二維碼關(guān)注

點(diǎn)贊分享是對作者最大的支持!
