Quick Tip: Using CSS Counters to Style Incremental Elements

In this quick tip, we’ll cover the very basics of CSS counters; a useful, yet not so well-known CSS feature. When we’re done building our demo, we’ll take a look at some real world examples of sites which take advantage of CSS counters.

The Goal: Styling an Ordered List

As a first step, let’s look at the layout we’ll be building:

Nothing fancy, right? Here’s the challenge though: we’ll be using semantic markup, avoiding the temptation to use unnecessary div and span elements to build those counter markers.

Let’s discuss a clean and flexible solution!

CSS Counters

All it takes to generate the aforementioned layout is to define an ordered list. At this point, you might be wondering if we could have used another element or even an unordered list. The short answer is “yes”, but keep in mind that an ordered list is the only element that accurately describes the structure of our page. 

You’ll then likely ask if it’s possible to fully customize the appearance of the ordered list numbers, building the desired layout that way. Styling the ordered list numbers would be really tricky. Thankfully though, there’s an alternative cross-browser approach, so let’s hide the default list numbers and take advantage of CSS counters instead.


CSS counters allow us to generate numbers based on repeated elements, and style them accordingly. Think of CSS counters as variables whose values can be incremented. Let’s look at the basic syntax:

Create a new counter
Create a new counter

Here we create a new counter on an ordered list and define its scope. We use the counter-reset property.

  1. The first value is the counter’s name
  2. followed by an optional parameter which defines the starting value of the counter (default: 0). Note that the counter will always start counting upwards, so the first generated value in our case will be 1.
styling the child element
Styling the child element

In this second diagram we can see that we’re styling the ::before pseudo-element of the li on our list.

  1. Here we’ve added the counter’s value to the content of our ::before. It’s worth mentioning that by using CSS counters with the content property, we’re able to concatenate (join) the generated numbers with strings.
  2. We refer to our counter’s name
  3. and define the counter’s style as being “decimal”. The possible values here are similar to those used for the list-style-type property.
  4. In the counter-increment rule we again refer to our counter’s name
  5. then use an optional parameter to indicate by how much the counter is incremented. The default value here is 1.


Based on what we’ve just discussed, here’s our markup:

And the related CSS:

This gives us the result as shown below:


At this point, it’s important to note that pseudo-elements aren’t 100% accessible. To test this I made a quick test. I installed NVDA and used Chrome 50, Firefox 45, and Internet Explorer 11 to preview the demo page. 

What I found is that when the Internet Explorer was used, the screen reader didn’t announce the generated content. These days the majority of screen readers recognize generated content of this kind, yet you should be aware of the possible limitations, and therefore decide which content is safe enough to generate using pseudo-elements.

CSS Counters in the Wild

Now that we know the basics of CSS counters, we’re ready to show a few examples that demonstrate their potential use cases. 

Firstly, CSS counters are commonly used in online newspapers. Most of the time, you’ll find them in sidebars: 

Wall Street Journal
Wall Street Journal

CSS counters can also be used within sections which describe steps, or give directions. Here’s just such an example:


Examples of Bloated HTML

In the previous section, we saw two online newspapers that take advantage of CSS counters. Now, let’s see another two newspapers which use bloated markup (albeit with accessible content) instead of CSS counters:

Washington Post
Washington Post


In this quick tip, we learned how we can use CSS counters to style ordered list items. Let’s briefly summarize what we’ve covered:

  • CSS counters are a great solution for every project that requires dynamic ordering with custom styles. On the other hand, this isn’t a fully accessible solution, so be aware of its limitations and use it properly.
  • To set up the counters, we have to specify two properties (i.e. counter-reset,counter-increment) and one function (counter() or counters()).
  • Pseudo-elements are responsible for displaying the counters. Remember that’s happening via the content property, which is only available to pseudo-elements.

Have you ever used CSS counters in your projects? If yes, be sure to share with us your work!

Leave a comment

Your email address will not be published.