Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

CSS counters

An <ol> list numbers its items by itself. But sometimes numbers are needed where there is no list: on article headings, instruction steps, figures. For this CSS has counters — named number variables that the browser increases as it walks through the page.

Three steps

Working with a counter always has three parts: create it, increase it and print it. counter-reset creates a counter with the value 0, counter-increment adds one, and the counter() function in the content property of a pseudo-element shows the current value:

<style>
  .steps { counter-reset: step; }
  .steps p { counter-increment: step; }
  .steps p::before { content: "Step " counter(step) ": "; font-weight: bold; }
</style>
 
<div class="steps">
  <p>Grind the coffee.</p>
  <p>Heat the water.</p>
  <p>Pour it over and wait four minutes.</p>
</div>

There are no numbers in the markup — CSS added them. Add one more paragraph, and the numbering continues by itself.

Properties and functions

CodeWhat it does
counter-reset: stepcreates the counter step equal to 0
counter-reset: step 10creates a counter with the value 10
counter-increment: stepadds 1
counter-increment: step 5adds 5 (negative works too)
counter(step)prints the value
counter(step, upper-roman)prints it in another style: I, II, III

As the second argument counter() accepts the same styles as list-style-type: lower-alpha, upper-roman, decimal-leading-zero.

Numbered headings

There can be several counters. A typical example is sections and subsections of a document: with every new h2 the subsection counter starts over:

<style>
  article { counter-reset: section; }
  h2 { counter-increment: section; counter-reset: sub; font-size: 20px; }
  h3 { counter-increment: sub; font-size: 16px; }
  h2::before { content: counter(section) ". "; }
  h3::before { content: counter(section) "." counter(sub) " "; }
</style>
 
<article>
  <h2>Installation</h2>
  <h3>Requirements</h3>
  <h3>Download</h3>
  <h2>Setup</h2>
  <h3>First run</h3>
</article>

The subsections of the second section start again from 2.1: counter-reset: sub on the h2 reset the counter.

Nested numbering: counters()

For lists of any depth there is the counters() function, with an s at the end. Each nested <ol> creates a new copy of the counter, and counters() prints all copies from the outer one to the inner one with the given separator:

<style>
  ol { counter-reset: item; list-style: none; padding-left: 20px; }
  li { counter-increment: item; }
  li::before { content: counters(item, ".") ". "; color: steelblue; }
</style>
 
<ol>
  <li>Introduction</li>
  <li>Basics
    <ol>
      <li>Tags</li>
      <li>Attributes
        <ol>
          <li>Global</li>
        </ol>
      </li>
    </ol>
  </li>
  <li>Summary</li>
</ol>

list-style: none removed the standard numbers so they are not shown twice.

Your own style: @counter-style

The @counter-style rule describes your own numbering system. For example, system: cyclic goes through the symbols in a loop:

<style>
  @counter-style stars {
    system: cyclic;
    symbols: "★" "☆";
    suffix: " ";
  }
  ul { list-style: stars; }
</style>
 
<ul>
  <li>Cappuccino</li>
  <li>Latte</li>
  <li>Flat white</li>
</ul>

A ready style is used in list-style and in the second argument of counter(). The rule is supported in all major browsers.

Common mistake

counter-reset on the same element that increases the counter. Each paragraph creates the counter from zero again and then adds one — every one gets 1:

<style>
  .bad p { counter-reset: n; counter-increment: n; }
  .good { counter-reset: n; }
  .good p { counter-increment: n; }
  p::before { content: counter(n) ". "; }
</style>
 
<div class="bad"><p>First</p><p>Second</p></div>
<div class="good"><p>First</p><p>Second</p></div>

Create the counter on the common parent, and increase it on the elements inside.

Thanks for reading!

Donate to the site — we work hard for you.