Understanding CSS Counters and Their Use Cases

Share this article

There are certain CSS features that we probably don’t use very often. I think CSS counters fall into that category for most of us, and more than likely for two reasons:

  1. They don’t seem to have many use cases.
  2. The code to write them is a bit complex.

I recently saw a practical use case for counters, so I thought I would give a brief crash course in how counters are written and share that use case here.

A Crash Course in CSS Counters

CSS counters allow you to number items in CSS using dynamic numbering, similar to how an ordered list works. But CSS counters are quite different. This feature uses a pseudo-element combined with some counter-specific CSS to append/prepend a dynamic “count” to a specified set of elements.

Here is a code example, similar to the one I’ll be using in the demo at the end of this article:

.container {
  counter-reset: issues 0;
}

.issue:before {
  counter-increment: issues 1;
  content: "Issue " counter(issues, decimal);
  display: block;
}

The first declaration block defines the scope of the count. What this means is my counter will increment only within elements that have a class of .container. I’ve chosen a custom identifier called “issues”, which is required to link the container to the elements being counted.

The second declaration block uses the :before pseudo-element (I could alternatively use :after, but that would be rare in a counter) and the content property to prepend the defined content.

As part of the content property’s value, I’m using the counter() function along with a string, similar to something that might be done in JavaScript or other more typical programming language. The counter() function takes two arguments: the counter identifier defined earlier (in this case, “issues”) and the counter style, which can be any value used for the list-style-type property in ordered lists. The default is “decimal”, which I’m using in this example.

If you’re still confused how counters work, maybe this mini infographic will help:

CSS Counters Infographic

And if that’s not enough, here are a few extra resources with more info, including my own article where I originally published a similar infographic:

That last link is the editors draft of the counters spec, which introduces some brand new counter-related features that probably don’t have much, if any, browser support and which might be at risk in future versions of the spec. The features I’m using in this article, however, are cross-browser, going back to IE8.

Determining the Value of CSS Counters

At a superficial glance, two major problems arise when first thinking about implementing CSS counters:

  1. Ordered lists already do this, so why would I need a feature so complex just to number items?
  2. Generated content is not accessible and this is mixing content with presentation.

The first of those two problems is really not a problem at all. If you want consecutive items numbered then it would be appropriate to use an ordered list (i.e. an <ol> with nested <li> elements). But CSS counters are not for numbering consecutive items; they’re for numbering non-consecutive items, wherever they might be in the DOM, then being able to re-order them without the need to change the number prepended to each.

Additionally, although counters can be a little complex looking at first glance, once you grasp the concept of CSS’s pseudo-elements, they really aren’t that difficult to modify and maintain.

The other problem, related to accessibility, doesn’t seem to be as big a problem as it was in the past. An article by Léonie Watson concluded:

“[G]enerated content is accessibility supported in most browsers, and recognised by screen readers accordingly.”

Support, however, is not 100%, so I would say that if you’re going to use pseudo-elements to generate content, the “content” should be of decorative value and not crucial to the understanding or functionality of the website it’s included in. With that balanced approach in mind, it should be fine to use counters in certain cases like the one described below.

A Simple Use Case

Recently I was looking at the W3C’s Selectors Level 4 spec and noted that they have “issues” and “examples” interspersed within the content. I’ve seen this before but only then did I decide to investigate it a little bit. These elements are numbered, so I wondered how they were able to add and remove them without needing to re-number the whole set each time. I figured it was maybe a script, or else generated on the back-end or something like that.

Nope. They’re using CSS counters, as indicated in the screenshot below:

W3C's use of CSS counters

In their page, they have numbered issues (the red boxes) and numbered examples (the yellow boxes). Using a custom identifier for each counted set, they can easily add, remove, or even re-order the items and the CSS will automatically add the correct numbers to the items.

In addition, these spec pages also include an Issues Index at the end of the page, which uses the same counter identifier as the issues, but in a new scope so it starts the count fresh. The duplicate issues list does create a little more work to maintain the issues but, once again, the order is generally easy to maintain as long as it matches what’s been changed in the content body.

A Drag-and-drop Demo

I’ve recreated the W3C’s example so you can fiddle around with how counters work, but also to see how easy it is to create dynamic lists in this way from non-adjacent items with just HTML and CSS.

See the Pen 20fe8f19ae48c210da6c5df78c0cf6f8 by SitePoint (@SitePoint) on CodePen.

In the demo, I’m using jQueryUI’s Sortable feature to let you drag and re-order any of the paragraphs on the page, including the “issue” and “example” boxes. Note how the numbers change depending on where the items are dragged (although the behavior of the number seems to be a bit quirky while in the process of dragging). I’ve also included a duplicate “Issues List” at the bottom, like on the W3C’s pages.

Conclusion

This should make it a little more clear what CSS counters can be used for. Think of any document that gets edited often, maybe even something user generated where the items can be re-sorted or re-ordered. And, as mentioned, these kinds of counters are most likely to be useful when the numbering isn’t vital to the understanding of the content and when the items are non-adjacent within the source.

If you’ve seen CSS counters used in some other useful way, let us know in the comments.

Frequently Asked Questions (FAQs) about CSS Counters

What are the different types of CSS counters?

CSS counters come in two types: ‘counter’ and ‘counters’. The ‘counter’ type is used for single-level counters, such as numbering headings in a document. The ‘counters’ type, on the other hand, is used for multi-level counters, such as numbering sub-sections within sections. Both types are used with the ‘content’ property in CSS to display the counter’s value.

How do I reset a CSS counter?

CSS counters can be reset using the ‘counter-reset’ property. This property sets the counter to any given number. For example, ‘counter-reset: section;’ will reset the ‘section’ counter to zero. You can also set the counter to a different number, like ‘counter-reset: section 5;’, which will reset the ‘section’ counter to five.

Can I use CSS counters with lists?

Yes, CSS counters can be used with lists. This is particularly useful when you want to customize the numbering of list items. You can use the ‘counter-reset’ and ‘counter-increment’ properties to control the numbering, and the ‘content’ property to display the counter’s value.

How do I style the numbers generated by CSS counters?

The numbers generated by CSS counters can be styled just like any other text in CSS. You can use properties like ‘color’, ‘font-size’, ‘font-weight’, etc., to style the numbers. The styles will be applied to the numbers when they are generated by the ‘content’ property.

Can I use CSS counters to number tables?

Yes, CSS counters can be used to number tables. This can be done by using the ‘counter-reset’ property on the ‘table’ element, the ‘counter-increment’ property on the ‘tr’ element, and the ‘content’ property on a ‘before’ or ‘after’ pseudo-element within the ‘tr’ element.

How do I create a multi-level counter with CSS counters?

Multi-level counters can be created using the ‘counters’ function in CSS. This function takes two arguments: the name of the counter and a string to be used as a separator between levels. For example, ‘content: counters(section, “.”);’ will create a multi-level counter with periods as separators.

Can I use CSS counters with pseudo-elements?

Yes, CSS counters are often used with the ‘before’ and ‘after’ pseudo-elements. The ‘content’ property, which is used to display the counter’s value, can only be used with these pseudo-elements.

How do I increment a CSS counter?

A CSS counter can be incremented using the ‘counter-increment’ property. This property increases the value of the counter by one each time it is invoked. For example, ‘counter-increment: section;’ will increase the ‘section’ counter by one.

Can I use negative numbers with CSS counters?

Yes, CSS counters can use negative numbers. This can be done by setting the ‘counter-reset’ or ‘counter-increment’ property to a negative number. For example, ‘counter-reset: section -1;’ will set the ‘section’ counter to negative one.

Can I use CSS counters with other CSS properties?

Yes, CSS counters can be used with other CSS properties. For example, you can use the ‘counter’ or ‘counters’ function with the ‘content’ property to display the counter’s value. You can also use the ‘counter-reset’ and ‘counter-increment’ properties with any element to control the counter’s value.

Louis LazarisLouis Lazaris
View Author

Louis is a front-end developer, writer, and author who has been involved in the web dev industry since 2000. He blogs at Impressive Webs and curates Web Tools Weekly, a newsletter for front-end developers with a focus on tools.

css counterslearn-advanced-cssLouisL
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week