Also available in: Français

CSS, since its version 2.1, offers a relatively unknown counter system due to an old incompatibility on IE. Some of you will probably defend the following position: CSS is not made for that, you have to use JavaScript. So be it! But know that it exists, and discover how to use it. Small introduction!

This blog post is a translation from the original french article written in 2012. Keep this history in mind 🙂

As I told you, the counters exist and are defined since CSS2.1 by the W3C. The arrival of CSS3 allowed to complete the definition a bit and to include it in a module called “Generated and Replaced Content“.

In this article, we will play with three properties and one function:

  • counter-reset: this property allows you to initialize a counter (create it). To do this, you need to fill in one or more counter names followed by its initial numerical value.
    counter-reset: count1 4 count2 0;

    Here we’ve got two initialized counters: count1 which starts at 4, and count2 which starts at 0.

  • counter-set : this property allows you to redefine the value of a counter, without creating a new one. To do this, fill in one or more existing counter names followed by its new numerical value.
    For example:
    counter-set: count1 0 count2 3;

    Here we have two counters redefined: count1 which restarts at 0, and count2 which restarts at 3.

  • counter-increment : this property allows you to increment a counter. To do this, enter the name of one or more counters, each followed by the number to be incremented. Without number following the counter name, the increment will be +1 by default.
    For example:
    counter-increment: count1 2 count2 4;

    Here our two initial counters will be increased by 2 for count1 and 4 for count2.

  • counter(): this function associated with the pseudo-element ::before or ::after and the content property allows you to insert the counter in your page. This generates a dynamic content. It takes one parameter and a second optional parameter. The first one is the counter name, the second one is the counter style. (same values as list-style-type)
    For example:
    li::before {
    content: counter(count1, decimal-leading-zero) " – ";

    In this example, the content of a li element will be preceded by a content type of “04 -“.

About the style of the counter, it is possible to specify the values “disc”, “circle”, “square” and “none”, so it is possible to generate nothing. I haven’t found any real use case for these values yet.

As I write these lines, the counter-set property is not recognized by any browsers but Firefox.

Counter CSS Démo

The simplest way to present those CSS Counters is to give you a well-organized document with a few headings at different levels.
Here is the demonstration:
CSS Counters Demo

The code used in HTML is relatively simple: make sure you have h2, h3 and h4 in a block of text, for example. I give you a snippet if you want to test :

<h2>This is the new way of life</h2>
<p>Lorem ipsum dolor sit amet, […]</p>

<h3>Lorem ipsum dolor sit amet, consectetur</h3>

<h4>Adipisicing elit</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing[…]</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do […]</p>

<h4>Anim id est laborum</h4>
<p>Lorem ipsum […]</p>

<h3>Reprehenderit in voluptate</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore[…]</p>

<h2>Come back later</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore […]</p>

The CSS is relatively short when it comes to counters, you just have to pay attention to the details: when counters are initiated and incremented.

/* we initiate counters named
title2, title3 and title4 */
body {
counter-reset: title2 title3 title4;

/* we increment value of title2
when we meet a h2 */
h2 {
counter-increment: title2 1;

/* then we generate a content before
the element composed by the number
in roman letter and un dash symbol */
h2::before {
content: counter(title2, upper-roman) " – ";

h3 {
counter-increment: title3 1;

h3::before {
content: counter(title3, decimal) " – ";

h4 {
counter-increment: title4 1;

/* here, we compose the counter
the number of the previous
title level, and a letter of
the current counter. */
h4::before {
content: counter(title3, decimal) "." counter(title4, lower-alpha) " – ";

CSS Counters demo on an odered list

You’re going to tell me: What’s the point since the ol list is already numbered?
Yes, that’s true, but the use of the generated content allows to apply richer styles thanks to CSS.
An example in image (and code):


There is a lot of stuff to know about lists, especially ol elements. Discover more about attribute start, reversed and type of counters.

Don’t hesitate if you have any question.