I needed a numbered list of blog posts to be listed with the last/high first and going down from there. Like this:
5. Post Title
4. Post Title
3. Post Title
2. Post Title
1. Post Title
But the above is just text. I wanted to do this with a semantic <ol>
element.
The easy way
This can be done using HTML’ s reversed
property on the <ol>
:
<ol reversed>
<li>This</li>
<li>List</li>
<li>Will Be</li>
<li>Numbered In</li>
<li>Reverse</li>
</ol>
For most people, this would be enough. Job done.
But I needed custom styles for the counters.
Let it be known that custom list number styles can be done with the ::marker
pseudo-element, but that isn’t yet supported by Chrome (although I hear it’s coming soon).
Because I wanted fully cross-browser compatible custom number styles, I went with custom counters.
Adding and styling a custom counter
Styling the counters of an ordered list differently from the rest of the list requires disabling the default counters and creating and show our own using CSS Counters. Chris shared a few recipes a while back that are worth checking out.
Assuming we have the following HTML:
<ol class="fancy-numbered">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ol>
…we first need to disable the default counters that come with all ordered lists by setting the CSS property list-style-type
to none
like so:
ol.fancy-numbered {
list-style-type: none;
}
That takes out all the default numbering. Next, we create a counter in CSS to track the number of items in the list.
ol.fancy-numbered {
list-style-type: none;
counter-reset: a;
}
This gives us a counter named “a” but it can be called it whatever you like. Let’s display our counter using the ::before
pseudo-element on the list item (<li>
).
ol.fancy-numbered li::before {
content: counter(a)'.';
}
This will set the content of the pseudo-element to the value of our counter. Right now, that will print 1’s next to your list item.
We need to tell the CSS counter how to increment.
ol.fancy-numbered li::before {
content: counter(a)'.';
counter-increment: a;
}
The starting value of “a” is zero, which seems weird, but the default increment is 1, meaning that becomes the actual starting point. Incrementing up by 1 just happens to be the default, but we can change that as we’ll soon see.
We can now proceed to apply any custom styles we want to the counter, because the counter is just a text pseudo-element that is wide open to styling:
ol.fancy-numbered li::before {
content: counter(a)'.';
counter-increment: a;
position: absolute;
left: 0;
color: blue;
font-size: 4rem;
}
For example, here, we’ve made the counter color blue and increased the font size. These are things that we couldn’t do using the default counter.
Reversing custom counters
If we add the reversed
property to the <ol>
element like we did before, we will observe no effect because we disabled the default numbering. That’s just what this property does.
<ol class="fancy-numbered" reversed>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ol>
The code above has no effect on our custom numbering. It’s still probably a good idea to leave it on there, since our intention is to reverse the list. This keeps things semantically accurate.
To reverse the visual order of our counter-based numbering, we need to know the total number of items in the list and instruct the counter to start from that number and then decrement from there.
ol.fancy-numbered {
counter-reset: a 4;
list-style-type: none;
}
Here, we’re setting counter-reset
to 4. In other words, we’re telling the browser to start the count at 4 instead of 1. We use 4 instead of 3, again, because the counter()
rule is applied to the first item on the list, which is 0. But, in the case where we’re counting backwards, 4 becomes our 0. If we started from 3 and decremented, wind up at 0 instead of 1.
Next, we alter our counter-increment
rule to decrease by 1 rather than increase, by making it a negative integer.
ol.fancy-numbered li:before {
content: counter(a)'.';
counter-increment: a -1;
position: absolute;
left: 0;
color: blue;
font-size: 4rem;
}
And that’s it! Now the world is your oyster for stuff like step trackers:
Or how about a timeline:
Maybe a business plan?
Cool article, I didn’t know about custom counters.
It would be super cool if we could do this without hardcoding max number. For example, can we just inverse elements using flex-box or something?
Thanks for sharing this with us!
Hi Maxim!
Glad you liked the article.
One simple way of making the counter more ‘dynamic’ would be setting the
counter-reset
property inline.That way, you could get the total number of items on the list, with JavaScript for example or if you were fetching from a backend, and then append the correct value.
Something like:
That’s how I usually handle it.
This was exactly what I needed to read! Thank you.