The CSS2.1 spec introduced a new technique allowing developers to combine three CSS properties and a pseudo-element to create auto-incrementing counters — similar to what is displayed in an ordered list.

While counters for lists are limited to <ol> or <ul> elements and only with simple incrementation, the new counter method introduced in CSS2.1 allows for integers to be prepended to any set of elements, and is quite flexible.

This technique is a bit confusing because it uses multiple CSS properties, and looks different than most CSS code. I hope to clarify how it’s used and I’ll run down some possible ways it can be implemented, along with some benefits and drawbacks.

The Syntax

Here’s what the code for a typical CSS counter looks like:

div.section { counter-reset: headings 0; } h2:before { counter-increment: headings 1; content: "Chapter " counter(headings, decimal) ": "; }

As mentioned, there are three CSS properties involved: counter-reset , counter-increment , and content . If any one of these is omitted, the technique will not work (the values, however, are more flexible, as you’ll see).

Syntax Breakdown

Here’s a breakdown of the two declaration blocks shown above and what the property/value pairs accomplish:

The Scope Indicator

The first declaration block (the selector div.section ) identifies what section in your markup will contain the set of elements that will have the auto-incrementing integers. It’s important to note the distinction of this declaration block from the one following. This particular element (the <div> ) will not receive a prepended integer value. This is just the “container” or “scope” wherein the actual incrementing elements will exist.

When the name of the counter is identified, it creates an instance of that specific counter that will be used in the following declaration block.

Counter-Reset

The counter-reset property must be used in conjunction with the selector that identifies the scope, as just discussed. The first part of the value is a custom name that you can give to the counter. This value is required. The name can be anything you want, as long as it doesn’t conflict with reserved words in CSS (for example, you can’t use the names “none”, “inherit”, or “initial”. And evidently you shouldn’t use the name “paged-media” for a counter, but I didn’t have any trouble getting that to work).

The second value for counter-reset is optional. The default is “0”. This value tells the numbered set of elements where the counter is reset, so the count begins one integer after the reset value. Therefore, if you set this value to “0”, the count will begin at “1”. If you set it to “-5”, the counter will start at “-4”, and so on.

The Numbered Elements

The second declaration block (the h2 selector) uses the :before pseudo-element to tell your document to place specific content (using the content property) inside all targeted elements (in this case the <h2> elements), “before” their content.

Counter-Increment

The counter-increment property identifies which scope the counter is actually associated with. So the first value (which is required) is the matching custom-named counter from the counter-reset property in the scope identifier from the first declaration block.

The second value in the counter-increment property is optional, and represents the amount by which you want the prepended integers to increment (or decrement if you use a negative value). The default is “1”.

The Prepended Content

Finally, the document is told by means of the content property exactly what content should be prepended to each element in the identified element set (the <h2> elements).

When used in conjunction with CSS counters, the only required value for the content property is the counter() function, but normally you will add other content (including whitespace) before and/or after (as I’ve done in the example above) to make the numbering look cleaner.

The counter() Function

The counter() function can take two comma-delimited arguments. The first argument tells the document to insert the current value of the named counter. The second argument is optional and tells the counter what style the integers should have. The default style is “decimal”, but can also be “upper-roman”, “upper-alpha”, and so on (the same as the list-style-type property for ordered lists).

You can also use a counters() function (plural), and you can nest counters, but for simplicity I won’t go into those right now.

A Graphic Summary

If the above seems a bit complex, here’s an infographic that describes the primary parts that comprise a CSS counter:

Browser Support and Drawbacks

Because of the cascade, multiple counters applied to the same scope need to be declared together, instead of one after the other. So this would not work:

div.numbered { counter-reset: headings 0 } div.numbered { counter-reset: subheads 0 }

Only the second reset counter will take effect, because it overwrites the previous one. So instead you need to declare both counters at the same time, like this:

div.numbered { counter-reset: headings 0 subheads 0 }

A potential drawback to using counters is the fact that you’re mixing content with presentation. Of course, this is not necessarily a problem with counters, but more of a problem with the content property. So, while the counters technique is flexible and useful, it does cause the line between content and presentation to be a bit blurred.

As far as browser support, the three properties and the pseudo-element that comprise CSS counter functionality are not supported in IE7 and lower, and have varying levels of partial and buggy support in IE8, Opera, and Safari. Firefox and Chrome offer the most support, all things considered.

UPDATE: In the comments, Fritz pointed out that CSS counters are not good for accessibility. This is basically because generated content (via the content property) is not accessible by current screen readers, as this article explains. If anyone has any further info on this subject, feel free to comment.

Benefits and Practical Uses

CSS counters are beneficial to a project for the obvious reason that they are programmatic and don’t require shuffling around of numeric values in your content. Similar to ordered lists, since the content doesn’t have the actual numbering, you can insert elements, remove elements, and switch elements around, and the numbering will intuitively correct itself.

Conversely, if you hard code incrementing numbers into your content, you have to correct the numbers any time you add or remove content. Thus, if counters were more widely supported by current browsers, they would be a huge benefit to a site’s overall maintenance.

Some practical uses might include:

Chapter names/numbers (as in the code example shown above)

Numbered table rows and/or table cells

Numbered HTML headings for lists (for list posts?)

To improve/change the look or incrementation value of regular ordered lists

Can We Use CSS Counters Today?

Because of the lack support in IE6 and IE7, for client sites I would say CSS counters shouldn’t be used unless you can code or find a suitable fallback option. But for websites and web apps aimed at a technical user base, I think they would be an effective way to create incrementing numbering systems without having to resort to using back-end programming.

If you’ve used CSS counters in any of your projects, or if you can think of any other practical uses for them, feel free to offer your comment below.

I’ve also included a simple demo page that shows two CSS counters in action.