MarTech

Using CSS counters

CSS counters

CSS. Developers tend to either love it or hate it—sometimes depending on the day. Well, here’s a reason to love it: CSS counters.

Of course we can simply use an ordered list to count items on a web page, but that doesn’t always fit semantically. And CSS counters are a bit more flexible than boring old lists, in my opinion.

How to use CSS counters

When using CSS counters, there are four properties and one function we can work with: counter-reset, counter-increment, counter-set, content, and the counter() function.

counter-reset

We’ll use the counter-reset property to create our counter on the parent element of the items we wish to count. The property can accept two values: a counter’s name and a number from which to increment. The number value is optional and defaults to 0.

Note: The increment number can be a little confusing because the value provided is the starting point, so the first counted item will display the next incremented value.

1
2
3
4
5
#one {
	counter-reset: myCounter;
	counter-reset: myCounter 0; /* Same result as above */
	counter-reset: myCounter 3; /* Begin at 4 */
}

As the name suggests, counter-reset can also reset an existing counter.

counter-increment

The counter-increment property defines the increment on the specified counter. This property can accept one or two values: either the name of a counter to increment or the name of a counter plus a number specifying the increment amount. If only the name of a counter is provided, the default increment of 1 is used.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#one {
	counter-reset: myCounter;
}

#one .child {
	counter-increment: myCounter 1; /* 1, 2, 3, 4... */
	counter-increment: myCounter; /* Same result as above */
}

#two {
	counter-reset: yourCounter;
}

#two .child {
	counter-increment: yourCounter 3; /* 3, 6, 9, 12... */
}

counter-set

Now that we have defined our counters and their increments, we can set a starting point. That’s where counter-set comes in. This property accepts a counter name and the starting value of the counter. The element it’s used on will be the starting point for the counter-set value. Leaving the starting value out makes counter-set default to 0. In cases where you might have multiple counters on an element, you can use multiple name-value pairs. You can also set counter-set to none to cancel a less specific counter-set style rule.

Note: We could leave out this property to let the counting start at the default of 1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#one {
	counter-reset: myCounter;
}

#one .child {
	counter-increment: myCounter;
}

#one .child:first-of-type::before {
	counter-set: myCounter; /* Start at 0 */
	counter-set: myCounter 300; /* Start at 300 */
}

#one .nth-of-type(3)::before {
	counter-set: myCounter -2; /* 1, 2, -2, -1, 0, 1, 2, 3... */
}

#two {
	counter-reset: yourCounter;
}

#two .child {
	counter-increment: yourCounter 3;
}

counter()

The counter() function returns a string representing the value of the specified counter. This is how our counter will be displayed visually. The counter() function is generally used with pseudo-elements and the content property, but it could theoretically be used anywhere a string value is accepted.

To display our counter, we need to provide the counter name to the counter() function. The function accepts a second argument to define the style. Any valid list-style-type value is also valid here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#one {
	counter-reset: myCounter;
}

#one .child {
	counter-increment: myCounter;
}

#one .child::before {
	content: counter(myCounter);
	content: counter(myCounter, decimal); /* Same result as above */
}

#two {
	counter-reset: yourCounter;
}

#two .child {
	counter-increment: yourCounter 3;
}

#two .child::before {
	content: counter(yourCounter, lower-alpha);
}

Defining custom CSS counters

If the standard list-style-type values aren’t sufficient, you could define your own custom counter style with the @counter-style CSS at-rule. From the MDN Web Docs:

The initial version of CSS defined a set of useful counter styles. However, although more styles were added to this set of predefined styles over the years, this system proved too restrictive to fulfill the needs of worldwide typography. The @counter-style at-rule addresses this shortcoming in an open-ended manner, by allowing authors to define their own counter styles when the pre-defined styles aren’t fitting their needs.

I won’t get into @counter-style this time, but check out the tutorial on the @counter-style CSS at-rule over at Quackit. To see the rest of the CSS counter tools in action, take a look at this Codepen collection about CSS counters, and watch this video tutorial by Chris Coyier about ordered lists and CSS counters.

Using CSS counters is pretty easy once you understand the the few properties involved. I prefer CSS counters when the task is about styling. If you need proper list markup, this isn’t the method to use. (You’re probably looking for HTML lists.) Nevertheless, there’s a lot you can do with only a handful of CSS.