Counters

Counters are not a new topic in CSS. It was a part of the CSS Level 2 Specifications (Revision 1 to be precise) itself and hence has very high browser support.

All browsers except IE6 and IE7 have support for CSS Counters.

Applying roman numerals styling to the counter output

CSS

body {
  counter-reset: item-counter;
}

.item {
  counter-increment: item-counter;
}

.item:before {
  content: counter(item-counter, upper-roman) ". "; /* by specifying the upper-roman as style the output would be in roman numbers */
}

HTML

<div class='item'>Item No: 1</div>
<div class='item'>Item No: 2</div>
<div class='item'>Item No: 3</div>

In the above example, the counter's output would be displayed as I, II, III (roman numbers) instead of the usual 1, 2, 3 as the developer has explicitly specified the counter's style.

Number each item using CSS Counter

CSS

body {
  counter-reset: item-counter; /* create the counter */
}
.item {
  counter-increment: item-counter; /* increment the counter every time an element with class "item" is encountered */
}
.item-header:before {
  content: counter(item-counter) ". "; /* print the value of the counter before the header and append a "." to it */
}

/* just for demo */

.item {
  border: 1px solid;
  height: 100px;
  margin-bottom: 10px;
}
.item-header {
  border-bottom: 1px solid;
  height: 40px;
  line-height: 40px;
  padding: 5px;
}
.item-content {
  padding: 8px;
}

HTML

<div class='item'>
  <div class='item-header'>Item 1 Header</div>
  <div class='item-content'>Lorem Ipsum Dolor Sit Amet....</div>
</div>
<div class='item'>
  <div class='item-header'>Item 2 Header</div>
  <div class='item-content'>Lorem Ipsum Dolor Sit Amet....</div>
</div>
<div class='item'>
  <div class='item-header'>Item 3 Header</div>
  <div class='item-content'>Lorem Ipsum Dolor Sit Amet....</div>
</div>

The above example numbers every "item" in the page and adds the item's number before its header (using content property of .item-header element's :before pseudo). A live demo of this code is available here.

Implementing multi-level numbering using CSS counters

CSS

ul {
  list-style: none;
  counter-reset: list-item-number; /* self nesting counter as name is same for all levels */
}
li {
  counter-increment: list-item-number;
}
li:before {
  content: counters(list-item-number, ".") " "; /* usage of counters() function means value of counters at all higher levels are combined before printing */
}

HTML

<ul>
  <li>Level 1
    <ul>
      <li>Level 1.1
        <ul>
          <li>Level 1.1.1</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Level 2
    <ul>
      <li>Level 2.1
        <ul>
          <li>Level 2.1.1</li>
          <li>Level 2.1.2</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Level 3</li>
</ul>

The above is an example of multi-level numbering using CSS counters. It makes use of the self-nesting concept of counters. Self nesting is a concept where if an element already has a counter with the given name but is having to create another then it creates it as a child of the existing counter. Here, the second level ul already inherits the list-item-number counter from its parent but then has to create its own list-item-number (for its children li) and so creates list-item-number[1] (counter for second level) and nests it under list-item-number[0] (counter for first level). Thus it achieves the multi-level numbering.

The output is printed using the counters() function instead of the counter() function because the counters() function is designed to prefix the value of all higher level counters (parent) when printing the output.