Using CSS Counters

The CSS counters are variables which we can increment or decrement and display in our HTML. Using them, we can achieve iterations as we do in a programming language.

We can create automatically ordered list in a new, creative way. Although the basic concept is similar to the <ol> element, the result differs. In this way, we can set up an order in every way in our markup. It is a less known feature like calc() function.

Set Up a CSS Counter

To control your counters, you need the counter-reset and counter-increment property, the counter() and counters() functions. All of this won’t worth a penny without the counter display, for that we can use the content property. The CSS content property is our way to display anything in our HTML through the stylesheet.

Next, you will see a simple example. First, we reset our counter and give it a name (issue) in the parent .issues element. After this, we increment our value and display it on the .issue items using the content property.

.issues {
    counter-reset: issue;
}

.issue::before {
    counter-increment: issue;
    content: "Issue " counter(issue) " ";
}
<div class="issues">
    <p class="issue"></p>
    <p class="issue"></p>
    <p class="issue"></p>
    <p class="issue"></p>
</div>

Define and Initialize with the counter-reset Property

We can define and initialize our counter variable with the counter-reset property; for this, we have to give any name and an optionally start value.

The default start value is zero. We have to define this on any parent (not just direct parent) container; parent of the elements where we want to display the counter values.

.our-element {
    counter-reset: <custom-ident> <integer>;
    counter-reset: issue;
    counter-reset: issue 2;
}

By default, only the name required. If we don’t set a start value, it will be zero. We can declare any integer value, negatives too.

Increment or Decrement the Value with the counter-increment Property

With the counter-increment property, we can increase or decrease our counter value. The property also has an optional second value which specifies the increment/decrement volume.

The first parameter of the counter-increment is our variable which we modify on each loop (when we find an element in the named scope set with counter-reset).

.our-element {
    counter-increment: <counter name> <integer>;
    counter-increment: issue;
    counter-increment: issue 3;
    counter-increment: issue -1;
}

By default, the increment value is one. We can set any integer, so if we set three, it will be adding three to the base value always. Note that the name is required because we can have more than one counter in one section.

Display the Values with counter() and counters() Functions

In the end, we have to display our counter(s). For this, we can use the counter() function in the content property.

The function has two parameters:

  • the first is the name of the counter which is required,
  • the second is the style of the display, which has a default value.

To display the counter’s value, we have to use the ::before or ::after pseudo ’element’s content property.

.our-element::before {
    content: counter(<counter-ident>, <counter-style>);
    content: "Issue " counter(issue) " ";
    content: "Issue " counter(issue, lower-roman) " ";
}
Note: in CSS, there aren’t any concatenation operator if you want to connect two value in the content property use space.

We have a bunch of list-style versions which you can see on MDN.

The counters() function does the same job as the singular version. The main difference is that with the counters() you can embed a counter iterations to another like in a multi-level <ol> list.

It has three parameters:

  • the first is the name of the counter,
  • the second is the separator which separates the embedded counters from each other,
  • the third is the counter type (optional).
.issues {
    counter-reset: issue;
}

.issue::before {
    counter-increment: issue;
    content: "Issue " counters(issue, ".") " ";
}
<div class="issues">
    <p class="issue"></p>
    <p class="issue"></p>
    <div class="issues">
        <p class="issue"></p>
        <p class="issue"></p>
    </div>
</div>

CSS Counters in Practice

Giving a practical example is usually harder than writing about the theory. For me, this kind of techniques is useful when I’m at a concrete problem. But for this, I first must know about the feature. I’m sure that after this article you will have an idea when you need this solution. Until then, let’s see some practical example!

Automatic Documentation Issue Tracking

This solution can be handy when you have some repetitive blocks, and you also want to count them. It can be a documentation page like in our CodePen example or a “Popular Posts” widget section where you want to be stylish.

See the Pen
CSS Counter Example
by Adam Laki (@adamlaki)
on CodePen.

We create a counter-reset on our .issues wrapper element. After this, we set a counter-increment for the items with issue class name. On the final step, we write out the value of the counter.

The great thing is that no meter how we modify our issues, orders always get an ordered numbering. For a real-life CSS counter example, you can check out Cone’s reference page where we mention our references in an ordered way.

Counting Checked Checkboxes

Using the input fields :checked pseudo-class value we can check if a checkbox is checked and if so we can increment our counter. Can be useful from a UX perspective.

See the Pen
Checkbox Counter
by Adam Laki (@adamlaki)
on CodePen.

Other Use Cases

CSS Counters Summary in a Video

Steve Griffith made an excellent and informative overall video on this topic. It is covering almost everything you need to know about CSS counters.

Need a web developer? Maybe we can help, get in touch!