Automatic Heading Numbers with CSS
Introduction
I've played around with automatic heading numbering before but always thought it needed to be done through scripting. I only found out this week (from Ivan Herman) that you can do it with CSS. Not only that, it's been around for years (it's in CSS 2.1). Ah well, you learn something new every day.
What Am I Trying To Do?
I want to create a CSS file that I can link to that will automatically number headings and not have to think about it - include a link to the stylesheet and it should "just do it."
Constraint: start at h2
I use h1
for the title of the page and I always make the content of h1 match the title
element - so that should not be part of the numbering. The first heading to be numbered should therefore
be the first h2
element.
Constraint: make it possible switch numbering off for a given heading
There are some circumstances in which it's useful to be able to include a heading that isn't
part of the numbering so we need to be able to switch it off. Looking at what others have done
the usual way is to define a class of nocount
.
So for demonstration purposes, here's an h3
that doesn't increment the counter.
This heading has no number
And switch it back on again …
This heading has a number
And picks up where the previous numbered one left off.
Constraint: it needs to work across all 6 levels
HTML5 defines 6 levels of heading (i.e. h1
through h6
) so I need to make
a single CSS file that will cover the extreme, rarely encountered in my life so far but it could happen,
case where a document used all those levels and numbered them.
Here's an h4
Blah blah
Here's an h5
Blah blah
Here's an h6
Just a quick check - everything still working as it should?
Here's another h4
Blah blah
Here's another h5
Blah blah
Here's another h6
Blah blah
What Am I not trying to do?
In this case, I don't want to style the headings - that's a separate task. This is just about the numbers.
And what about section
elements?
I really like the section
element that HTML5 introduces, as well as aside
,
header
, footer
etc. and I generally use them. The algorithm for defining the
outline numbering is part of the HTML5 spec and the
Mozilla
Developer pages [broken link removed] are really good on this. Personally, I have trained myself to make sure I use
headings at the right level so, unless I make a mistake, I'll only use an h4
within the scope
of an h3
. That said, I will usually preceed each heading with a section
element. I believe
the idea of always beginning a section with an h1
element has lost favour - good, because that
seemed to lead to the need to define all sorts of extra CSS just to make an h1
look like the h3
you actually meant it to be.
Bottom line: I fully understand the usefulness of sections but, for this exercise, I'm going to ignore them and
just focus on the hn
elements.
The CSS
Time to actually put the CSS on show:
body {counter-reset: h2} h2 {counter-reset: h3} h3 {counter-reset: h4} h4 {counter-reset: h5} h5 {counter-reset: h6} h2:before {counter-increment: h2; content: counter(h2) ". "} h3:before {counter-increment: h3; content: counter(h2) "." counter(h3) ". "} h4:before {counter-increment: h4; content: counter(h2) "." counter(h3) "." counter(h4) ". "} h5:before {counter-increment: h5; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". "} h6:before {counter-increment: h6; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". "} h2.nocount:before, h3.nocount:before, h4.nocount:before, h5.nocount:before, h6.nocount:before { content: ""; counter-increment: none }
If the W3C spec is
too dense (and I admit they generally are), then David Storey provides a good explanation in his article
Automatic numbering with CSS Counters
and little is served by my repeating his explanation. Basically you first define your counters (by resetting them) and then
you increment and insert them as generated content using the :before
psuedo class.
Watch the cascade!
I wanted to use as few lines of CSS as possible so I first tried this:
h2 {counter-reset:h2; counter-reset:h3; counter-reset:h4; counter-reset:h5; counter-reset:h6;}
See why that doesn't work? It's the C in CSS - the cascade. You're provding a series of different values for the same property and each one replaces the other so that in fact the only counter that gets reset here is the last one.
Use It By All Means
If this is useful to you, by all means use it. If you use it directly from https://philarcher.org/css/numberheadings.css then no attribution is necessasry. Otherwise please treat it as being released under CC BY.
Just because I can …
…I thought I'd end with some …
Pointless extra headings
All of which should …
… be numbered…
properly.
All the Way down to h6
So that works?
Yep. That should do it.