bscure CSS: Implicit List-Item Counter
A few years ago I wanted to share one little-known CSS feature — a built-in list-item
counter for ordered lists. But then there were a few browser issues preventing us from using it fully. Now, given that most of those bugs are fixed, we can try starting using them for our lists.
ntro
I don’t want to go into all the details of using CSS for styling listsGo to a sidenote but would like to start right from what I would be talking about.
Let’s say we want to changeGo to a sidenote the ordered list’s markers to have brackets after the numbers rather than dots:
Side note: If you’d want to read more about lists in CSS, other than reading the specs, I can recommend this in-depth article by Rachel Andrew: “CSS Lists, Markers, and Counters”. Jump to this sidenote’s context.
Side note: The live examples in this article would have some extra styles with them — these would be just styles for my blog, which conveniently are using what I’m talking in this article about (with some CSS variables thrown in for convenience). Jump to this sidenote’s context.
ol > li {
list-style-type: none;
}
ol > li::before {
content: counter(list-item) ') ';
}
<ol>
<li>First item</li>
<li>And the second one</li>
</ol>
You might notice that in the example above there are just two declarations — and no sign of counter-reset
and counter-increment
. This is intended and it works!
hat the Specs Say
Let me copy a bitGo to a sidenote from the CSS Lists and Counters spec.
In addition to any explicitly defined counters that authors write in their styles, list items automatically increment a special
list-item
counter, which is used when generating the default marker string on list items[…]
In all other respects, the
list-item
counter behaves like any other counter and can be used and manipulated by authors to adjust list item styling or for other purposes.
In the specs, some examples take an advantage of such implicit counters — showing how they would work properly with various attributes on the <ol>
and <li>
such as start
and value
.
start
, value
, and reversed
bscure HTML list attributes: Did you know? Also not a very well-known aspect, this time of HTMLGo to a sidenote — we have a native way to control the initial number from which the item would start, adjust a particular item’s value, or reverseGo to a sidenote the count direction. Look at these examples:
<ol start="42">
<li>A good start</li>
<li>And a continuation</li>
</ol>
<ol>
<li>First item</li>
<li value="42">And then an adjusted one</li>
<li>The following would continue from the previous</li>
</ol>
<ol reversed>
<li>This item takes the last place</li>
<li>This item could do better</li>
<li>The item that wins this unnecessary competition</li>
</ol>
Neat, right? If we would go and try to implement the same behavior from scratch using completely custom CSS counters, it would be much more complicated than those two declarations at the start of the article, but thankfully, we can utilize built-in implicit counters,
and for a lot of cases we could stop writing custom counter-reset
and counter-increment
completely.
But this was not always the way it is now.
ld Bugs
Here is my originalGo to a sidenote experiment where I first tested all of this — https://codepen.io/kizu/pen/QaKjmJ — Firefox did not support this at all, and Chrome/Safari did have bugs. The perfect implementation at that time was in Edge!
Here is a list of the issues I stumbledGo to a sidenote over at the time:
- Mozilla — reported by David Baron in April of 2005, fixed in March of 2019.
- Webkit — reported by me in December of 2017, fixed in January of 2018 (wow, fast).
- Chromium — reported by me in December of 2017, fixed in July of 2020.
The most serious issue was, of course, the absence of the implementation in Firefox, but the other issues in Chromium and Webkit could be a bit annoying when you would try to override the display of the counters and then use the HTML attributes to control them.
cknowledgements
When first did my experiments with the counters, I didn’t find any mentions of the implicit list-item counters except for the specsGo to a sidenote. Since then there were a few mentions of them:
- In a 2019 “CSS Lists, Markers, And Counters” article on Smashing Magazine by Rachel Andrew — following the fix in Mozilla she uses extensively this implicit counter in the examples.
- In a 2020 “Custom bullets with CSS
::marker
” article by Adam Argyle and Oriol Brufau — mentions using it for overriding the display of ordered lists'::marker
s.
I would explain the low coverage of this CSS feature first by its absence in Firefox, and then by some of the issues that were present at the time.
::marker
he Why I’m not writing about the ::marker
? There are a few reasons. The main being quite poor browser support at the current moment (May 2022) — while Firefox implemented it in 2019 and Chrome in 2020, and Safari supports only styling of its color
and font
, limiting what we can do with it quite drastically.
However, the things would be the same for the ::marker
— it also has the access to the implicit list-item
counter, so if you’re ok with the way Safari doesn’t yet support overriding content
on it, we can already start using it, but I would say, given we have a way to support all browsers including Safari by using ::before
— we should better do this.
ccessibility
I’m not an accessibility expert, so I’m not sure if things did improve, but at least in 2019
there was an issue where Safari/VoiceOver could lose the role of the list, here is a good article about it — “Fixing” Lists by Scott O’Hara. The gist is — even though it is generally not recommended to duplicate the role of the elements that have it intrinsically, we might want to still add a role="list"
to our lists if we’re heavily styling them (and not to forget to test things, making sure the content is available to everyone).
Hopefully, the support for ::marker
would be one day perfect, so there won’t be a need to override the list-style
, but even we would need to be careful.
inal Words
If you’re using custom list styling in your code and you have used custom counters — you might think about retiring them and start using the built-in list-item
. Even more — if you have some kind of user-generated content, and there is a chance there’d be a list with start
, value
or reversed
— there is a big chance those won’t work with anything except for the list-item
counter. So I hope this post would be helpful.
And, once again: reading specs is one of the best ways to learn what CSS is capable of, and it is possible to find some real gems there. And if those things are obscure — there is a chance they’re not very well tested and you could find bugs that you could report, in the end helping improve the way we write CSS.
Let me know what you think about this article on Mastodon!
Published on with tags: #Practical #CSS Counters #Typography #CSS