CSS Counters – The Right Way to Organize Your Ordered Content

It is pretty common to see step-based content. Tutorials, shopping carts, FAQ’s, grandma’s recipes. You know, numbers and steps are really good to grab attention, so many writers use this.

But, talking about HTML how should we write it? Most (all?) use numbers as text in headings, as they were common content.

Well, let me tell you a secret: They are doing it wrong.

Actually we are doing it wrong ( nothing against this fantastic post of Ruben, just take a look at how we do the numbers, directly in HTML as text ).

A little time ago I was wondering about this thing, isn’t it more a CSS job? Actually yeah, it is. We have to keep content in HTML and presentation in CSS, and since we may want other ways to order titles, they are all about presentation. But, how can we do this kind of thing? One class for each item? That would be terrible!

Then CSS counter property comes to save us. It is a pretty unknown property that allows us to perform a simple count via CSS. It will be better explained with our demos :D

So, let’s rock!


Take a look at what you will do at the end of this tutorial:

I think you should check out the demo, and download it to try out a little bit more!

So, counter?

Basically a counter is a “variable” that we can create with CSS but the only two possible operations that we can perform with it is to increase or to reset. For such operations we can use counter-reset or counter-increment CSS properties.

A basic usage is the first case mentioned in this post, the organized content. So let’s say you have a multi-step tutorial and want it organized automatically, what you have to do is just add this to your CSS:

body {
  counter-reset: first; /* our h1's counter is zero every time we have a body tag (hope only once) */
h1 {
  counter-increment: first; /* so, when we have one h1, our counter will increase one unit */
  counter-reset: second; /* and we will reset our h2's counter */
h1:before { /* wow, here we will append a pretty formated Step N - Item */
  content: "Step " counter(first) " - "; /* when you write counter(first) we will get its current value */
  font-size: 0.8em;
  font-weight: normal;
  font-style: italic;
  color: #bababa;
h2 {
  counter-increment: second; /* so our h2's counter goes up.. */
  counter-reset: third; /* and we reset the h3's */
h2:before {
  content: counter(first) "." counter(second) " - "; /* we will output H1NUMBER.H2NUMBER */
h3 {
  counter-increment: third; /* h3 goes up, up, up */
h3:before {
  content: counter(first) "." counter(second) "." counter(third) " - "; /* and we output H1.H2.H3 */

As you can see its usage is quite simple. Our downside is that we rely on content: property and after (or before) pseudo-element so older browsers won’t see this. But it should work just fine in IE8+ and other browsers.

Multiple counters

Another great thing is that you can have a “general” counter, you just have to separate multiple counters to increase with spaces. Just like this:

body {
  counter-reset: general first;
h1 {
  counter-increment: general first;
  counter-reset: second;
h2 {
  counter-increment: general second;
  counter-reset: third;
h3 {
  counter-increment: general third;

Better Ordered lists

Using almost the same code, you can create better ordered lists, with sub-items control.  So instead of just 1 – ITEM you can have – ITEM when you have multiple nested OL’s. This is the code I’d use:

ol {
	list-style: none;
	counter-reset: olfirst; /* our father OL must have olfirst item reseted */
	font-family: arial;
ol ol {
  counter-reset: olsecond; /* our sub OL's reset the olsecond, third must to be olthird and so on */
	ol li {
		counter-increment: olfirst; /* when we have a item that is children of first OL, it increases first counter*/
	ol li ol li {
		counter-increment: olsecond; /* when the item is children of a OL that is children of another OL, so it is a sub OL */
	ol li:before {
		content: counter(olfirst) " - "; /* let's output our pretty number */
	ol li ol li:before {
		content: counter(olfirst) "." counter(olsecond) " - "; /* let's output our "sub-number" */

Are you hungry yet?

This is a pretty tricky attribute so you must to try it out a couple of times until you are familiar with it. But we have some tutorials at W3Schools about CSS counter reset, CSS counter increment and beforeafter pseudo elements that can help you a lot.

So, it is time for you to talk. Did you know about this property What do you think about it?

Rochester Oliveira

I'm a web designer and entrepreneur from Itajubá (MG), Brasil. I love writing about obscure topics and doing some cool stuff. And also I do some FREE stuff, check it out: http://www.roch.com.br/

15 Smart Tools To Help You Build Your Freelance Business

Discover the awesome tools we use in making our clients comfortable and happy in learning new things every day.

Download Now


  1. says

    Never even knew that existed, cool! :) Too bad browser support, specifically <IE8, don't support it, and so many people are still using those ancient browsers :(

  2. Ziogas Chris says

    Really nice tutorial. I didn’t know about this functionality.

  3. Ralph says

    Great article! Very interesting too. I thought you were talking about a new CSS3 property, but it’s a CSS2.1 property. Never heard of it and I never seen it used by someone else in its stylesheet. Anyways great post and I can see the benefits of it.

    • says

      Hey Ralph,

      Yeah, it is that kind of unknown but useful CSS properties… You just have to pay attention about :before and :after browser support!


  4. Brecht Billiet says

    Very nice indeed.

    At first i thought you want to replace the ordered list by css counters, which in my opinion is a bad idea because you loose your htmlstructure which is very important to SEO and Smartphones/tablets.
    After that i saw you were just overriding them.
    Very nice post! Keep up the good work