CSS Reference Concept

Counters

CSS Counters provide us with a way to apply automatic numbering using CSS.

Basically, it allows us to number a list of elements of any type, the same way ordered lists are numbered. Numbers are then incremented per element, and displayed as generated content using CSS pseudo-elements. Using the corresponding CSS property, you can initialize a counter(s), and then specify the increment value, which specifies by how much the counter should be incremented for every occurrence of the element.

Counters can be useful for numbering sections in articles, for example, or figures (images), and for tables of contents, among other use cases. They have several advantages over manually numbering elements. Not only can manual numbering be daunting, but it can be very tiresome to update all elements if one or more are added or removed and the order of the elements changes. However, using automatic numbering, the order and numbers will be updated no matter how many elements are added or removed.

The Properties

CSS counters are controlled with two properties:

The counter(s) is then displayed using either the counter() function (or the counters() function) of the content property used to generate content using the ::before pseudo-element. See the content property entry for more information.

The counter-reset property

counter-reset: [ <identifier> <integer>? ]+ | none | inherit
                

The counter-reset property is used to define and initialize one or more CSS counters. It takes one or more identifiers as a value, which specify the names of the counters. Each counter name is optionally followed by an optional <integer> value that specifies the initial value of the counter. The keywords none, inherit and initial must not be used as counter names.

The initial value of the counter is not, however, the first number/value that is displayed when the counter is displayed. This means that if you want your counter to start displaying from one (1), you’ll need to set the initial value in counter-reset to zero. Zero is the default initial value, so if you omit it, it will be reset to zero by default. Negative values are allowed. So, if you want your counter to start displaying from zero, you can set its initial value to -1.

The counter-reset property also takes either none or inherit as values. none will unset a counter, and inherit will inherit the counter reset value from the element’s parent. The default value for the counter-reset property is none.

A counter is reset on an element like so:

article {
    counter-reset: my-counter; /* equivalent to: counter-reset: my-counter 0; */
}
                

The following are all valid counter-reset values:

counter-reset: section 4; /* counter starts displaying at 5 */
counter-reset: counter_2;
counter-reset: number-system 10;
                

The counter-reset property is used in conjunction with the counter-increment property. For more information on how to use the counter-reset property to create counters, see the Using Counters section below.

The counter-increment property

counter-increment: [ <identifier> <integer>? ]+ | none | inherit
                

The counter-increment property is used to specify the increment value for one or more CSS counters. It takes one or more identifiers as a value, which specify the names of the counters that are to be incremented. Each counter name is optionally followed by an optional <integer> value that indicates by how much the counter is incremented for every occurrence of the element that you’re numbering. The default increment is 1. Zero and negative integers are allowed. If a negative integer is specified, the counter is decremented.

The following is an example defining a counter using the counter-reset property, and then specifying that is will be incremented by one (the default value used if you don’t specify an integer value) for every occurrence of an h2 heading inside an article:

article {
    /* define and reset counter */
    counter-reset: section; /* 'section' is the name of the counter */
}

article h2 {
    /* increment the counter by 1 for every occurrence of the h2 heading */
    counter-increment: section; /* equivalent to counter-increment: section 1; */
}
                

The following are all valid counter-increment values:

counter-increment: my-counter 2; /* increment 'my-counter' by 2 for every occurrence of the element */
counter-increment: list_item;
counter-increment: SomeCounterName222 3; /* increments the counter 'SomeCounterName222' by 2 for every occurrence of the element */
counter-increment: silly-name -1; /* will decrement the counter by 1 for every occurrence of the element */
                

The counter-increment property is used in conjunction with the counter-reset property. For more information on how to use the counter-increment property to increment counters, see the Using Counters section below.

The counter() function

The counter() function is used with the content property to display a CSS counter. It takes a CSS counter name as an argument, and is passed as a value to the content property, which is used to display the counter as generated content using the :before pseudo-element.

h2:before {
    content: counter(counter-name);
}
                

The counter() function has two forms: counter(name) and counter(name, style). The name argument is the name of the counter that is to be displayed. The name of the counter is specified using the counter-reset property.

The style argument defines the style of the counter. By default, counters are formatted with decimal numbers—that is, counters are generated in the form of numbers—but all the styles available for the list-style-type property are also available for counters. This means that you can create decimal number counters, counters displayed as roman characters, lower-alpha characters, among others. The following are all possible counter styles:

disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit
                

See the list-style-type property entry for a description of each style.

The following is an example specifying that a counter is to be displayed using lower-roman characters:

ul li:before {
    content: counter(my-counter, lower-roman);
}
                

See the Using Counters section below for examples on setting up and using CSS counters, and the Styling Counters section for examples showing other counter styles in use.

The counters() function

The counters() function is used with the content property to display a CSS counter. It is passed as a value to the content property, which is used to display the counter as generated content using the :before pseudo-element.

The counters() function has two forms: counters(name, string) and counters(name, string, style). The name argument is the name of the counter that is to be displayed. The name of the counter is specified using the counter-reset property.

The counters() function, as opposed to the singular form counter(), is used to set up nested counters. Nested counters are used to provide automatic numbering for nested elements, such as nested lists. If you were to apply a counter to a nested list, the first level items could be numbered, for example, as 1, 2, 3, etc. Second level list items would be numbered 1.1, 1.2, 1.3, etc. Third level items would be 1.1.1, 1.1.2, 1.1.3, 1.2.1, 1.2.2, 1.2.3, etc.

The string argument is used as a separator between the numbers of the different nested levels. For example, in ‘1.1.2’, the dot (‘.’) is used to separate the different level numbers. If you were to specify the dot as a separator using the counters() function, it could look like this:

content: counters(counterName, ".");
                

If you want the nested counters to be separated by another character, for example if you want them to be displayed as “1-1-2”, you could use the dash instead of the dot as the string value:

content: counters(counterName, "-");
                

The style argument defines the style of the counter. By default, counters are formatted with decimal numbers—that is, counters are generated in the form of numbers—but all the styles available for the list-style-type property are also available for counters. This means that you can create decimal number counters, counters displayed as roman characters, lower-alpha characters, among others. The following are all possible counter styles:

disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit
                

See the list-style-type property entry for a description of each style.

The following is an example specifying that the nested counter is to be displayed using lower-roman characters, and it uses a dot as a separator:

ul li:before {
    content: counters(my-counter, ".", lower-roman);
}
                

See the Using Counters section below for examples on setting up and using CSS counters, the Nesting Counters section for an example and live demo using nested counters, and the Styling Counters section for examples showing other counter styles in use.

Setting Up and Using CSS Counters

Let’s start with a simple example. We’re going to number sections of an article. The numbers should be applied to the heading of each section.

In order to create and use a CSS counter, the following steps are followed:

  • Choose a name for the counter and reset it to an initial value of your choice. This is done using the counter-reset property. Initializing the counter (specifying a start value) is optional—if you don’t specify one, it will start at zero.

    The counter-reset property is set on an ancestor or sibling of the element you’re numbering. For example, if you’re numbering headings in an article, you could set the counter on an ancestor of these headings.

    article {
        /* Set up a counter called "my-counter", and initialize it to 0 */
        counter-reset: my-counter 0;
    }
                            

    The reason behind this is that resetting the counter on the numbered element will result in all occurrences of that element having the same number. This is because the counter will be reset to its initial value and then incremented by the increment value for each heading before it is displayed.

    See the Multiple Counters section below for an example of when to set a counter up on the element’s sibling.

  • Specify when the counter increments, and by what value. For example, if you want the counter to increment at every occurrence of an h2 heading, you’ll specify that. This is done using the counter-increment property. You can choose to increment the counter by any value you want for every occurrence of the element you’re numbering (the h2 in our case). By default, the counter will increment by one. You can even use negative values (the counter would then be decremented).

    h2 {
        /*  use the "my-counter" counter for every occurrence of an h2
            and increment it by 1 (the default value) for each occurrence */
        counter-increment: my-counter 1;
    }
                            

    One important thing to note here is that a counter is incremented before it is displayed, so if you want the first heading to start at one, you should set the initial value of the counter to be zero in the counter-reset property.

  • After having set up a counter and specified when and by how much it should be incremented, you need to display that counter.

    To display a counter, you’ll need to use the counter() function (or counters() for nested counters) of the content property as a value for the ::before pseudo-element.

    In our example, we’re numbering the h2 headings, so we’re going to display the counter before the heading:

    h2::before {
        content: counter(my-counter);
    }
                            

    Of course, you will probably want to add some white space and possible any other separator between the number and the title of the heading, so you can do that by appending the separator to the counter in the counter() function (see the content property for more information on using strings as values):

    h2::before {
        /* adds a dot followed by white space after the number */
        content: counter(my-counter) ". "; 
    }
                            

The following is a live demo of the above code. Try changing the initial value of the counter and the increment value to see how that changes the numbering on the headings. Also try removing headings or adding headings in between others to see how the order is automatically rendered correctly.

View this demo on the Codrops Playground

Try applying both the counter properties (i.e resetting and incrementing the counter) to the headings in the above live demo to see how it affects the numbering.

Setting Up Multiple Counters

Suppose you wanna set up a “nested” counter. For example, suppose the article above contained sub-sections. A section’s title is represented as an h2, and sections titled with an h3 headline are supposed to be “sub-sections”. You may want to create a counter in this case that is reset in every section, and in that section the sub-sections are then numbered, just like the main sections were numbered in the previous demo.

In order to create nested counters in CSS, you can either use the counters() function, or declare and reset a counter on an element’s sibling.

The counters() function works only when you’re numbering nested elements that are actually nested in the markup. In the case of the article with sub-sections, the sub-sections are only visually sectioned, but in the markup, the headings are siblings, and you have no sections nested inside other sections. In this case, the counters() function will do no good, so we’re going to declare and reset two separate counters, instead of setting up two counters in the counters() function. See the next section for an example using the counters() function.

Here’s how this will go: We’ll set up a counter for the h2s (main sections) just as we did in the previous section above. Then, we’re going to set up another counter for the h3s (“sub-sections”), but instead of setting the counter up on the article, we’re going to reset it on the h2s. Here’s how the code looks like:

The markup:

<article>
    <h1>Article Headline - Not Numbered</h1>
    <p>...</p>
    <h2>Section heading</h2>
    <p>...</p>
    <h2>Section Heading</h2>
    <p>...</p>
    <h3>Sub-section</h3>
    <p>...</p>
    <h3>Sub-section</h3>
    <p>...</p>
    <p>...</p>
    <h2>Section Heading</h2>
    <p>...</p>
    <h3>Sub-section</h3>
    <p>...</p>
    <h3>Sub-section</h3>
    <p>...</p>
    <h3>Sub-section</h3>
    <p>...</p>
    <!-- you get the picture.. -->
</article>
                

Notice how the sub-sections are actually siblings of the other sections in the markup. That’s why we won’t be using the counters() function to create the nested counters.

The CSS for creating the nested counters looks like the following:

article {
    counter-reset: my-counter;
}
h2 {
    counter-increment: my-counter;
    /* reset a new counter in each section */
    counter-reset: sub-counter;
}
h2:before {
    content: counter(my-counter) ". ";
}
h3 {
    /* start/increment counter for each sub-section */
    counter-increment: sub-counter;
}
                

In each section, the sub-counter is going to be reset. Then “inside” that section, for every “sub-section”, it will start numbering from the beginning.

All that is left is to display the counter for the h3s. If you were to do this:

h3:before {
    content: counter(sub-counter);
}
                

..the sub-counter will be displayed, but it will number the sub-sections as 1, 2, 3, etc. That would be okay. However, if you want each sub-section to be more related to the section that it belongs to, you’re probably going to want to display the numbers as: 1.1, 1.2, 1.3, etc. for the sub-sections of the first section, and then 2.1, 2.2, 2.3, etc. for sub-sections of the second section.

In order to do that, you can display both the first counter and the sub-counter, and connect them with a dot, by appending the strings together in the content property value like this:

h3:before {
    content: counter(my-counter) "." counter(sub-counter) " ";
}
                

The following is a live demo of the code. Try adding/removing sections and sub-sections (h2s and h3s) to see how the counters adapt and maintain the order.

View this demo on the Codrops Playground

Setting Up Nested Counters

In the previous examples, we kind of “faked” nested counters by using two different counters and setting them up on elements that are visually nested but are actually siblings in the markup.

Using the counters() function, we can, however, set up multiple counters in one declaration, and these counters will be nested by default. We’ll use the counters() function in this example to set up nested counters on a nested list. Lists (ul, ol) can be nested down to several levels in the markup, so we can use counters() with them.

We’re going to create a counter such that the nested levels inside the list will receive the same numbering style as the sub-sections in the previous example of the previous section.

As in the previous sections, it’s important to know where to set up and reset the counter. In the case of lists, you will usually be resetting the counter at the top level of the list, and then increment it on the list items:

ul {
    counter-reset: nested-counter;
}

ul li {
    counter-increment: nested-counter;
}
                

Displaying the counters is straightforward. We’ll be using a dot as a separator between the nested counters, and we’ll add a closing parenthesis as a separator between the counter and the text in the list item, just for a change.

ul li:before {
    /* the string inside the counters() function is the separator between the two counters
    and the string outside the function is the separator between the generated number and the text of the list item */
    content: counters(nested-counter, ".") ") ";
}
                

The following is a live demo of the nested counters applied to a three-level deep nested list:

View this demo on the Codrops Playground

Styling Counters

Counters are generated as decimal numbers by default. However, you can use any of the many list style types available for the list-style-type property to style counters as well. This means that you can create decimal number counters (which are the default), counters displayed as roman characters, lower-alpha characters, and other styles. The following are all possible counter styles:

disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit
                

The following is a demo that displays a counter using upper-case roman characters instead of decimal numbers. It displays a single counter to number the headings of sections in an article, just like the demo in the Using Counters section above. The upper-case roman characters style is provided inside the counter() function: counter(my-counter, upper-roman);.

View this demo on the Codrops Playground

The following example shows sections and sub-sections in an article using a lower-greek counter style. This is the same example as the example shown in the multiple counters section above. The lower greek style is applied to both the counters: counter(my-counter, lower-greek) "." counter(sub-counter, lower-greek) " ";.

View this demo on the Codrops Playground

In the following demo, we’re styling a nested counter applied to nested list items. This is the same demo from the nested counters section above. The style used to display the counter is the upper-alpha style, specified inside the counters() function: counters(nested-counter, ".", upper-alpha) ") ";.

View this demo on the Codrops Playground

You can even use circles, discs, and squares as values for counters, although they don’t usually make any sense. Counters, as their name suggests, are used to show some kind of count, and using squares and discs or circles, they won’t be any informative. Here is the previous demo using the square style:

View this demo on the Codrops Playground

Browser Support

CSS Counters

Method of controlling number values in generated content, using the `counter-reset` and `counter-increment` properties.

W3C Recommendation

Supported from the following versions:

Desktop

  • 4
  • 2
  • 8
  • 9
  • 3.1

Mobile / Tablet

  • 3.2
  • 2.1
  • 10
  • 56
  • 51

* denotes prefix required.

  • Supported:
  • Yes
  • No
  • Partially
  • Polyfill

Stats from caniuse.com

Written by

Last updated December 11, 2016 at 10:27 pm by Mary Lou

Do you have a suggestion, question or want to contribute? Submit an issue.