Lesson 32: Counters

Many types of content are best shown as an HTML list. For ordered list content, like recipe steps or footnotes for an article, the marker often carries information too. CSS gives you several ways to control the counters in a list.

List styles

There are a wide range of built-in list style types. They support numbers, letters, roman numerals, and many international counting systems.

On top of the styles browsers support, the W3C published Ready-made Counter Styles. These add support for 181 more styles in 45 writing systems.

If those options don’t fit your needs, you can also define a custom @counter-style. This lets you set your own symbols, a prefix and suffix, and more.

By default, the item marker sits outside the list, in front of the list, and right aligned. You can also put the item marker inside the list with list-style-position: inside.

Counters

List styles control how the list item markers look. Counters let you control the values that get shown. For <li> list item elements, the browser makes a counter called list-item. It goes up by 1 for each list item it meets.

CSS counters keep a running count of how many times an element with a counter-increment value is rendered.

To make a new counter, use counter-reset with a counter name and, if you like, a starting value. You will often set this on a parent element that holds all the elements you want to count.

[!NOTE] counter-reset starts a counter with an initial value and direction. Don’t confuse it with counter-set, which only sets the value of a counter that already exists.

Then add a counter-increment property on each element you want to count.

Finally, show the counter value with the counter() function.

In this example, we want to show the running count of footnotes as the link text for each footnote. We want a single counter for the whole document, so we set counter-reset: note on the body and increment on each footnote link.

You can also have several counters counting different items. In the footnotes example, what if you wanted to show the index of the section and paragraph that the footnote is in?

You can make the section count on the body using counter-reset, and then increment on each <h2> element. We want the paragraph count to reset for each section. So we use counter-reset on <h2> elements and increment on <p> elements.

Finally, we join the counter values in the content property.

a:after {
  content: "(S" counter(section) "P" counter(paragraph) "N" counter(note) ")";
  font-size: small;
  vertical-align: super;
}

Nested counters

What happens when you nest a list inside another list? The list-item counter starts over for each <ul> or <ol> element. Using counter() only returns the number of the innermost count. If you want to show the count from each nested counter, use the counters() function. It takes a counter name and a separator.

li::marker {
  content: counters(list-item, ".")
  }

Reversing counters

By default, counters start at 0 and count up by one for each element. This includes the built-in list-item counter for <ol> elements. So the first one is counted as 1. What if you want to count backwards to 1?

To do that, add the reversed attribute to the <ol>. If you are using the standard list style, the markers work as you expect. But if you are using a custom counter, you need to set counter-increment to a negative value. You also need to work out the start value for the counter yourself.


Adapted from Learn CSS © Google and contributors, licensed under CC BY 4.0 (prose) and Apache 2.0 (code samples).