CSS counters are one of those "oh cool, didn't know CSS could do this" type of fun features. In short, CSS allows you to continuously increase a certain amount without the need for JavaScript.
We start with this simple pagination example:
The numbers you see are not hardcoded In HTML, they are generated by the following CSS:
1
2
3
4
5
6
7
8
9
10
11
body {
counter-reset : pages; // initialize counter
}
a {
counter- increment : pages; // increment counter
}
a::before {
content : counter (pages); // display counter
}
Count properties follow the rules of "document appearance order". First encounter the Body element and initialize a counter called pages. Then when an a element is encountered, the pages counter is incremented and displayed.
You can have multiple counters with different names. This example has two counters with overlapping counting ranges, sections and boxes:
Related CSS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
body {
counter-reset : sections boxes;
}
section {
counter-increment : sections;
}
section::before {
content : 'Section ' counter (sections);
}
.box {
counter-increment : boxes;
}
.box::before {
content : counter (boxes, upper-roman );
}
Here you can see the syntax for initializing multiple counters at once (line 2). For a twist, the boxes counter is displayed as upper-roman (Line 18). All parameter options of display are the same as list-style-type attribute, here is the documentation.
Now we do something fun. Count attributes can be placed in pseudo-class selectors like :checked (Translator's Note: The original text is pseudo-selectors, but it is usually written as pseudo-classes selectors, so it is translated as pseudo-class selectors as usual). This allows the counter to reflect the user's selection via the checkbox. The following example counts how many items the user has selected.
The CSS is just a slight modification from the previous example. The only difference is that we increment it in the pseudo-class selector (input:checked) and only display it in a dedicated .total element.
1
2
3
4
5
6
7
8
9
10
11
body {
counter-reset : characters;
}
input:checked {
counter-increment : characters;
}
.total::after {
content : counter (characters);
}
does not have to increase by 1. You can add any amount you want. They can even have negative growth. Building on the previous example, this one sets a special increment for each selector.
The syntax is simple enough.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
body {
counter-reset : sum;
}
#a:checked { counter-increment : sum 64 ; }
#b:checked { counter-increment : sum 16 ; }
#c:checked { counter-increment : sum -32 ; }
#d:checked { counter-increment : sum 128; }
#e:checked { counter-increment : sum 4; }
#f:checked { counter-increment : sum -8 ; }
.sum::before {
content : '= ' counter (sum);
}
Back to the topic, you can also control the initial value of the counter.
1
2
3
body {
counter-reset : kittens 41 ; // starting out with 41 kittens
}
Display:none elements will not trigger counting. If you want to hide an element but still trigger the count, you have to hide it in another way. Here's one way:
1
2
3
4
input {
position : absolute ;
left : -9999px ;
}
Maybe you have noticed, This is exactly what I did in the last two examples. To demonstrate the effect, I've hidden the current checkboxes, but still need them to be counted when selected.
Great, browsers support CSS counting. Good luck~
CSS counters are amazing, but don’t forget our old friends
Update: I should mention accessibility. CSS counting relies on generated content within pseudo-class elements. Some screen readers will read it, some won't. Therefore, it is best not to rely on pseudo-class elements for critical content. Although the CSS counters in the examples are well designed, I would not use them unchanged in a production environment.
Fun times with CSS counters