Here’s an easy pagination example to get us started:
The numbers you see aren’t hardcoded in HTML. They’re generated in CSS with this:
Counter properties follow a “when this element is encountered in the document” flow. The
body element is encountered first, initializing a counter named pages. Then the
a elements are encountered, each one incrementing and displaying the pages counter.
You can have multiple counters just by using different names. This example has two overlapping counters, sections and boxes:
Here you can see the syntax for initializing multiple counters at once (line 2). And just to be extra saucy, the boxes counter is displayed as
upper-roman (line 18). The full list of display options is the same as the one for
list-style-type, documented here.
Counting User Selections
Now we’re getting to the fun stuff. Counter properties can be placed in pseudo-selectors like
:checked. This allows counters to react to user selections via checkboxes. Here’s an example that tallies how many selections a user has made:
The CSS is really not much of a leap from our previous examples. The only differences are that we’re incrementing the counter on a pseudo-selector (
input:checked) and displaying the counter just once in a dedicated
Counters don’t have to increment by 1. They can increment by any whole number you like. They can even decrement by using negative numbers. Building on our previous example, this one sets specific increment values for each selection:
The syntax is simple enough:
While we’re on the subject, you can also control the starting value of a counter:
An element with
display: none on it will not increment a counter. If you want to hide an element but still have it contribute to a counter, you’ll have to hide it another way. Here’s one option:
Maybe you noticed, this is exactly what I’m doing in the last two examples. I hide the actual checkboxes for the sake of presentation, but still need them to increment the counter when checked.
Browser support for CSS counters is fantastic. Green across the board.
As awesome as CSS counters are, don’t forget about our old friends
<li>. They’re still great for a basic list of enumerated items. It’s the trickier situations that benefit from CSS counters, especially since they work on any element, giving you more freedom syntactically and semantically.
Update: I should mention accessibility. CSS counters rely on generated content in pseudo-elements. Some screen readers will pick up this content, some won’t. Because of this, it’s best not to rely on pseudo-elements for critical content. These demos were crafted to teach CSS counters in interesting ways, but I wouldn’t apply them in production as-is.