Understanding CSS Counters and Their Use Cases

By Louis Lazaris

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.


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.

  • Mark Hkr

    This is awesome! I don’t know how I can use counters on a practical use case, now I have a nice idea for what can I use them in a project. Thanks!!

  • Will Boyd

    Nice write-up. Love that drag/drop demo!

    A couple more use cases I’ve come up with:

    • LouisLazaris

      Nice… I’ll have to read through your article, I haven’t seen that yet. Thanks!

  • M S i N Lund

    How good is the support in mobile browsers?

    That’s usually where the fun stops dead…

  • Pietro Grandi

    Thank you for this nice article! I didn’t yet know CSS counters!

  • Ralph Mason

    LOL → “CSS Counters” (

    Sorry, couldn’t resist. :p

    Great article, Louis. I can see how this might be really handy for numbering sections of a document on the fly—something I hadn’t considered before, but handy if you are adding and removing sections during editing etc.

  • Ralph Mason

    LOL → “CSS Counters” (

    Sorry, couldn’t resist. :p

    Great article, Louis. I can see how this might be really handy for numbering sections of a document on the fly—something I hadn’t considered before, but handy if you are adding and removing sections during editing etc.

  • Terry

    Probably a good idea to start using `::before` instead of `:before`. Double colons are used for pseudo-elements, single ones for pseudo-states.

    • LouisLazaris

      Good point!

      But I will say that I’m pretty sure the single colon syntax for pseudo-elements will probably be supported in all browsers forever, to ensure backwards compatibility. So, in a way, it’s almost pointless to switch. It just feels like it’s too late to make a change like that. I think the only benefit to that is for development reasons, being able to search through your own stylesheets to easily differentiate between pseudo-elements and pseudo-classes.

  • Pablo Sanfilippo

    Can I use with calc? I can think of pretty neat things to do with it and transitions.

  • Elliott Post

    I love you.



Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in Front-end, once a week, for free.