CSS counter計數器(content目錄序號自動遞增)詳解


一、CSS計數器三角關系

CSS計數器只能跟content屬性在一起的時候才有作用,而content屬性貌似專門用在before/after偽元素上的。於是,就有了,“計數器↔偽元素↔content屬性”的鐵三角關系。

二、CSS計數器成員

舉例班級中成員依次報名

其中有這么幾個關鍵點:
1. 班級命名。總不能六脈神劍一指,你,儂,汝來稱呼吧~有個稱呼,如生信4班,就知道誰的是誰了。
2. 報數規則。1,2,3,4遞增報數,還是1,2,1,2報數,讓班級的人知道。
3. 開始報數。不發口令,大眼瞪小眼,會亂了秩序。

巧的是,以上3個關鍵點正好對應CSS計數器的2個屬性和1個方法,依次是:
1. counter-reset
2. counter-increment
3. counter()/counters()

1. counter-reset


顧名思意,就是“計數器-重置”的意思。其實就是“班級命名”,主要作用就是給計數器起個名字。如果可能,順便告訴下從哪個數字開始計數。默認是0, 注意,默認是0而不是1. 可能有同學回疑惑,尼瑪網上的各種例子默認顯示的第1個數字不都是1嗎?那是因為受了counter-increment普照的影響,后面會詳細講解。

OK, 這里,我們先看兩個簡單的counter-reset的例子:

.xxx { counter-reset: small-apple; } /* 計數器名稱是'small-apple' */
.xxx { counter-reset: small-apple 2; } /* 計數器名稱是'small-apple', 並且默認起始值是2 */

demo:

.contaner1 {
counter-reset: number;
}

.contaner1:before {
content: counter(number);
}

.contaner2 {
counter-reset: number 1;
}

.contaner2:before {
content: counter(number);
}
<div class="row">
<div class="contaner1">定義一個名稱開始編號</div>
</div>
<div class="row">
<div class="contaner2">定義一個名稱開始編號,定義初始值為1</div>
</div>

  

counter-reset的計數重置可以是負數,例如-2。也可以寫成小數,例如2.99,不過就是IE和FireFox都不識別,認為是不合法數值,直接無視,當作默認值0來處理;不過Chrome不嫌貧嫉富,任何小數都是向下取整,如2.99當成2處理,於是王小二還是那個王小二。

到此為止?非也非也!counter-reset還有一手,就是多個計數器同時命名。例如,王小二和王小三同時登台:

demo:

.contaner5 {
counter-reset: number 3 number1 4;
}

.contaner5:before {
content: counter(number) '\A' counter(number1);
}
 
          
<div class="row">
<div class="contaner5">定義兩個計數器,第一個從3開始,第二個從4開始</div>
</div>
 

直接空格分隔,譬如逗號什么的都不行。

另外,counter-reset還可以設置為noneinherit. 干掉重置以及繼承重置。你懂的,就不展開了。

2. counter-increment

顧名思意,就是“計數器-遞增”的意思。值為counter-reset的1個或多個關鍵字。后面可以跟隨數字,表示每次計數的變化值。如果缺省,則使用默認變化值1(方便起見,下面的都使用默認值做說明)。

CSS的計數器的計數是有一套規則的,我將之形象地稱為“普照規則”。具體來講就是:普照源(counter-reset)唯一,每普照(counter-increment)1次,普照源增加1次計數值。

於是,我們可以解釋上面提到的“默認值是0”的問題。通常CSS計數器應用的時候,我們都會使用counter-increment, 肯定要用這個,否則怎么遞增呢!而且一般都是1次普照,正好+1,第一個計數的值就是1啦(0+1=1)!

下面,通過幾個例子,給大家形象地展示下普照規則

Demo相關核心代碼為:

.contaner3 {
counter-reset: number 1;
counter-increment: number;
}

.contaner3:before {
content: counter(number);
}
<div class="row">
<div class="contaner3">定義一個名稱開始編號,定義初始值為1,定義它的編碼規則 每次自增1(只有父元素)</div>
</div>

這里counter-increment普照了p標簽,counter-reset值增加,默認遞增1,於是計數從設置的初始值2變成了3wangxiaoer就是這里的計數器,自然偽元素content值counter(wangxiaoer)就是3.

當然,也可以普照自身,也就是counter-increment直接設置在子元素上:

.contaner7 {
counter-reset: number 1;
}

.contaner7:before {
counter-increment: number;
content: counter(number);
}

<div class="row">
<div class="contaner7">定義一個名稱開始編號,定義初始值為1,定義它的編碼規則 每次自增1(只有子元素)</div>
</div>
 

依然是1次普照,依舊全局的計數器+1,所以,顯示的數值還是3().

趁熱打鐵。如果父元素和子元素都被counter-increment普照1遍,結果會如何呢?

很簡單的,父元素1次普照,子元素1次普照,共兩次普照,counter-reset設置的計數器值增加2次,計數起始值是1,於是現實的數字就是3啦!

.contaner4 {
            counter-reset: number 1;
            counter-increment: number;
        }

        .contaner4:before {
            content: counter(number);
            counter-increment: number;
        }
<div class="row">
<div class="contaner4">定義一個名稱開始編號,定義初始值為1,定義它的編碼規則 每次自增1(父元素和子元素都有)</div>
</div>  

總而言之,無論位置在何方,只要有counter-increment,對應的計數器的值就會變化,counter()只是輸出而已!

理解了“普照規則”,則以我們通常的計數器遞增效果也可以理解了。

考慮下面這兩個問題:

  1. 爸爸受到普照,且重置默認值0,爸爸有2個孩子。孩子自身都沒有普照。兩個孩子的計數值是?
  2. 爸爸沒有普照,重置默認值0,爸爸有2個孩子。孩子自身都接受普照。兩個孩子的計數值是?

答案是:1,1和1,2!

哦?答案居然不一樣,有什么差別呢?

很簡單。什么爸爸,孩子你都不要關心。只要看被普照了幾次。情況1就爸爸被普照,因此,計數器增加1次,此時兩個孩子的counter自然都是1; 情況2,兩個孩子被普照,普照2次,第1個孩子普照之時,計數器+1,也就是1;第2個孩子普照之時再+1,於是就是2. 於是,兩個孩子的counter輸出就是1,2.

.row4 .contaner6:before {
            counter-increment: number;
            content: counter(number);
        }
        .row4 {
            counter-reset: number 1;
        }
<div class="row4 row">
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
</div>

  

計數器的數值變化遵循HTML渲染順序,遇到一個increment計數器就變化,什么時候counter輸出就輸出此時的計數值。看懂了下圖,您自然就會全然明白“普照規則”了。

計數器深入理解

counter-increment其他設定
counter-reset可以一次命名兩個計數器名稱,counter-increment自然有與之呼應的設定,也是名稱留空就可以了。

正如本節開始提到的,這變化的值不一定是1,我們可以靈活設置。例如:

counter-increment: counter 2

那就是偶數偶數的增加。例如下面這個變身:
遞增值大小變化變身

還可以是負數,例如:

counter-increment: counter -1
.row2 {
            counter-reset: number 0;
        }

        .row2 .contaner6:before {
            counter-increment: number -1;
            content: counter(number);
        }
<div class="row2 row ">
<div class="contaner6">自動標號--遞減--初始值是0(默認是0)----每次自減1(默認是1)</div>
<div class="contaner6">自動標號--遞減--初始值是0(默認是0)----每次自減1(默認是1)</div>
<div class="contaner6">自動標號--遞減--初始值是0(默認是0)----每次自減1(默認是1)</div>
<div class="contaner6">自動標號--遞減--初始值是0(默認是0)----每次自減1(默認是1)</div>
<div class="contaner6">自動標號--遞減--初始值是0(默認是0)----每次自減1(默認是1)</div>
<div class="contaner6">自動標號--遞減--初始值是0(默認是0)----每次自減1(默認是1)</div>
<div class="contaner6">自動標號--遞減--初始值是0(默認是0)----每次自減1(默認是1)</div>
</div>

  

就有了遞減排序效果啦!

值還可以是none或者inherit.

3. counter()/counters()


這是個方法,不是屬性。類似CSS3中才calc()計算。這里作用很單純顯示計數。不過名稱、用法有多個:
counter/counters語法

 目前為止,我們看到的是最簡單的用法:

counter(name) /* name就是counter-reset的名稱 */

 那下面這個語法是什么意思呢?

counter(name, style)

這里的style參數還有有些名堂的。其支持的關鍵字值就是list-style-type支持的那些值。作用是,我們遞增遞減可以不一定是數字,還可以是英文字母,或者羅馬文等。

list-style-type:disc | circle | square | decimal | lower-roman | upper-roman | lower-alpha | upper-alpha | none | armenian | cjk-ideographic | georgian | lower-greek | hebrew | hiragana | hiragana-iroha | katakana | katakana-iroha | lower-latin | upper-latin

.row1 {
            counter-reset: number 1;
        }
        .row1 .contaner6:before {
            counter-increment: number;
            content: counter(number,upper-roman);
        }
<div class="row1 row">
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
<div class="contaner6">自動標號-遞增---初始值是1---每次自增1(默認是1)</div>
</div>

  

 counter還支持級聯。也就是一個content屬性值可以有多個counter()方法。

上面CSS源代碼使用'\A'使用inline水平元素換行,此技術若有興趣,可參考之前的“使用CSS(Unicode字符)讓inline水平元素換行”一文。

 下面介紹下counters()方法。看似值多了個字母s, 但表意大變身。counters幾乎可以說是嵌套計數的代名詞。

我們平時的序號,不可能就只是1,2,3,4,.., 還會有諸如 1.1,1.2,1.3,...等的子序號。得,前者就是counter()干的事情,后者就是counters()干的事情。

基本用法為:

counters(name, string); /* MDN上說,要想IE8兼容,這里逗號后面的空格要去掉,但是鄙人IE11的IE8模式看,無此問題 */

其中,string參數為字符串(需要引號包圍的)(必須參數),表示子序號的連接字符串。例如1.1string就是'.'1-1就是'-'.

看上去很簡單。但是,如果理解不是很深刻,日后在使用肯定會遇到麻煩——“咦?怎么沒有子序列,明明語法正確的啊?”首先,記住這一句話,“普照源是唯一的”,所以,如果你在只在body標簽上設置counter-reset,就算里面的子元素嵌套了祖宗十八代,還是不會有任何嵌套序號出現的!

所以,要想實現嵌套,必須讓每一個列表容器擁有一個“普照源”,通過子輩對父輩的counter-reset重置、配合counters()方法才能實現計數嵌套效果。

.row3{ counter-reset:number 0;}
        .row3 .contaner6:before{
            counter-increment: number 1;
            content:counters(number,"-") '.';
        }
<div class="row3 row">
    <div class="contaner6">自動標號----第一級
        <div class="row3">
            <div class="contaner6">
                自動標號-----第二級
                <div class="row3">
                    <div class="contaner6">
                        自動標號-----第三級
                        <div class="row3">
                            <div class="contaner6">自動標號-----第四級</div>
                            <div class="contaner6">自動標號-----第四級</div>
                            <div class="contaner6">自動標號-----第四級</div>
                            <div class="contaner6">自動標號-----第四級</div>
                            <div class="contaner6">自動標號-----第四級</div>
                        </div>
                    </div>
                    <div class="contaner6">自動標號</div>
                    <div class="contaner6">自動標號</div>
                    <div class="contaner6">自動標號</div>
                    <div class="contaner6">自動標號</div>
                </div>
            </div>
            <div class="contaner6">自動標號</div>
            <div class="contaner6">自動標號</div>
            <div class="contaner6">自動標號</div>
            <div class="contaner6">自動標號</div>
        </div>
    </div>
    <div class="contaner6">自動標號</div>
    <div class="contaner6">自動標號</div>
    <div class="contaner6">自動標號</div>
    <div class="contaner6">自動標號</div>
    <div class="contaner6">自動標號</div>
</div>

  

也會遇到這樣的麻煩——“咦,怎么子序列不按層級順序來啊,命名語法正確啊?” 還是要記住這一句話:“一個容器里的普照源(reset)是唯一的”,所以,

如果你不小心把計數顯示和技術reset元素以兄弟元素形式放在一起(雖然HTML內容布局呈現是沒有異常的),就很可能會出現計數序號亂入的情況。

會看到標紅的部分的序號顯示異常了

計數器的值亂入的截圖示意

為何會出現這個問題,我們看下HTML(主要是注釋):

<div class="reset">
    <div class="counter">我是王小二</div>
    <div class="reset"><-- 這里的reset與上面的counter是兄弟關系,而不是父子關系。雖然布局渲染上沒有差異。但是,一個容器的reset的唯一的,一旦子元素出現reset,會改變整個容器的嵌套關系,於是,后面的“王小三”、“王小四”其實已經進入了2級嵌套,因此顯示的是1-3和1-4 -->
        ...
    </div>
    <div class="counter">我是王小三</div>
    <div class="counter">我是王小四</div>
    <div class="reset">
        <div class="counter">我是王小四的大兒子</div>
    </div>
</div>

如果上面的注釋沒看明白,您可以跟前面沒有問題的demo做下HTML結構對比,或許就會豁然開朗!

 counters()也是支持style自定義遞增形式的

counters(name, string, style)

counter()style參數使用一致,不贅述。

四、CSS計數器與display:none

一個元素,如果設置了counter-increment, 但是其display的屬性值是none或者含有hidden屬性(針對支持瀏覽器),則此計數值是不會增加的。而visibility:hidden以及其他聲明不會有此現象。

五、CSS計數器實際應用

相比傳統的ol,ul列表計數,CSS計數器的優勢就在於靈活與強大,不足就是IE6/IE7不支持。

普照規則第一條,普照源唯一。所以,我們可以在頭尾放兩個差距甚遠的列表,然后,這些列表自動顯示序號。而ol/ul只能寫死start實現,很不靈活,一旦列表有刪減,就嗝屁了。

由於計數器是偽元素控制顯示的。因此,我們幾乎可以應用各種CSS樣式,各種定位等。所以,基本上,只要有有序序號呈現的地方,就能使用CSS計數器。

例如,電商首頁的圖片slide廣告上的1,2,3,4,...序號;
首頁廣告位的序號
我們做分享時候使用的HTML5 web在線幻燈片就可以使用CSS計數器標注頁數等;以及一開始給小伙伴們做的果汁工具的3個選擇等。

參考文章


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM