In the code below, I need to use the div
tag at the top of the HTML for styling. Without the div
tag in place, the hx
tags are outline numbered correctly, but with the div
in place everything goes completely wrong. I need this to work like this, but with the div
tag still in place, and I need it to work for divs with different ids. Any ideas?
body {counter-reset: h1}
h1 {counter-reset: h2}
h2 {counter-reset: h3}
h1:before {counter-increment: h1; content: counter(h1) ". "}
h2:before {counter-increment: h2; content: counter(h1) "." counter(h2) ". "}
h3:before {counter-increment: h3; content: counter(h1) "." counter(h2) "." counter(h3) ". "}
<div class="varies">
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h1>
</div>
<p>Morbi efficitur nibh metus, a vehicula mauris tristique ac. Duis ornare metus eget iaculis hendrerit.</p>
<h2>Morbi nisi lacus, ultricies sit amet turpis a, aliquet congue nulla.</h2>
<p>Duis eget facilisis nisl.</p>
<h3>Donec tincidunt purus quam, ut accumsan lorem hendrerit a.</h3>
<p>Aenean in mattis quam.</p>
<h3>Maecenas a nulla sit amet ligula facilisis tincidunt lacinia non enim.</h3>
<p>Aliquam dignissim turpis placerat, facilisis magna et, venenatis purus.</p>
<h2>Suspendisse tempus eu elit nec malesuada.</h2>
<p>In ut sollicitudin nisi. Praesent non porttitor ante, molestie scelerisque mauris.</p>
<h2>Vivamus eu turpis efficitur, ornare risus in, consectetur tellus.</h2>
<p>Cras pellentesque orci eu placerat mollis.</p>
<h1>Duis eu nulla et tellus porttitor auctor.</h1>
The reason for the behavior can be explained in detail by having a look at what the W3C specs say about creation of counters, their scope and inheritance.
Counter Reset: The counter-reset property creates new counters on an element.
Scope of a Counter: The scope of a counter starts at the first element in the document that has a 'counter-reset' for that counter.
Counter Inheritance: A counter and its value are inherited separately, possibly from different elements. If an element has a previous sibling, it must inherit all of the sibling’s counters. Otherwise, if the element has a parent, it must inherit all of the parent’s counters. Otherwise, the element must have an empty set of counters. The element then inherits counter values from the immediately preceding element in document order.
In the working snippet (the one without the div
), the following is what happens:
counter.h1
(added a prefix to differentiate from element) is created (or reset) at body
and its initial value is set as 0. body
gets counter.h1
. When the first h1
is encountered, the value of counter.h1
is incremented to 1. When the next h1
is encountered, it inherits counter value from the previous element and then increments to 2.counter.h2
counter is created at h1
element and value is set to 0. This value is visible to the siblings of the h1
and they can all inherit it. h2
elements are actually siblings of the h1
element and so each h2
element inherits counter.h2
that was already created at the h1
and just increments its value. So, when the first h2
is encountered counter.h2
becomes 1 and so on.h2
elements, the h3
elements are also siblings of both the h1
and h2
elements and so they also inherit counter.h1
and counter.h2
. This is why the numbering remains correct in this sample.body {counter-reset: h1}
h1 {counter-reset: h2}
h2 {counter-reset: h3}
h1:before {counter-increment: h1; content: counter(h1)". "}
h2:before {counter-increment: h2; content: counter(h1)"." counter(h2)". "}
h3:before {counter-increment: h3; content: counter(h1)"." counter(h2)"." counter(h3)". "}
<!-- body creates counter.h1 and set to 0 -->
<h1>Heading 1 <!-- Inherits counter.h1 from parent, creates counter.h2 and set to 0 -->
<!-- ::before being a child inherits all counters from parent, increments counter.h1 to 1 and displays value -->
</h1>
<p>Paragraph</p>
<h2>Heading 2 <!-- Inherits counter.h1, counter.h2 from sibling, creates counter.h3 and set to 0 -->
<!-- ::before being a child inherits all counters from parent, increments counter.h2 to 1 and displays value -->
</h2>
<p>Paragraph</p>
<h3>Heading 3 <!-- Inherits counter.h1, counter.h2, counter.h3 -->
<!-- ::before being a child inherits all counters from parent, increments counter.h3 to 1 and displays value -->
</h3>
<p>Paragraph</p>
<h3>2nd Heading 3 <!-- Inherits counter.h1, counter.h2, counter.h3 -->
<!-- ::before being a child inherits all counters from parent, increments counter.h3 to 2 and displays value -->
</h3>
<p>Paragraph</p>
<h2>2nd Heading 2 <!-- Inherits counter.h1, counter.h2, counter.h3, resets counter.h3 to 0 -->
<!-- ::before being a child inherits all counters from parent, increments counter.h2 to 2 and displays value -->
</h2>
<p>Paragraph</p>
<h2>3rd Heading 2 <!-- Inherits counter.h1, counter.h2, counter.h3, resets counter.h3 to 0 -->
<!-- ::before being a child inherits all counters from parent, increments counter.h2 to 3 and displays value -->
</h2>
<p>Paragraph</p>
<h1>2nd Heading 1 <!-- Inherits counter.h1, counter.h2, counter.h3, resets counter.h2 to 0 -->
<!-- ::before being a child inherits all counters from parent, increments counter.h1 to 2 and displays value -->
</h1>
Now let us to come to the snippet that doesn't work (the one where the h1
is present within a div
).
h1
creates counter.h2
but this can be inherited only by the siblings of the h1
(of which there are none).h2
element is encountered, UA tries to increment value of counter.h2
within the :before
selector. But here the h2
parent does not inherit counter.h2
and hence h2:before
doesn't either. Because of this h2:before
will create its own counter.h2
and increment to 1. h2
elements also cannot inherit counter.h2
because the counter is created by h2:before
(which is a child of h2
). Because of this, each time a h2
is encountered a new counter is created within its :before
and incremented. This is why all h2
show up as 1.1. h3
elements know about counter.h2
and they don't increment it either and this is why they show up as 1.0.x. counter.h3
because it was created by h2
element which is a sibling of all h3
elements. This is why counter.h3
gets incremented properly.body {counter-reset: h1}
h1 {counter-reset: h2}
h2 {counter-reset: h3}
h1:before {counter-increment: h1; content: counter(h1)". "}
h2:before {counter-increment: h2; content: counter(h1)"." counter(h2)". "}
h3:before {counter-increment: h3; content: counter(h1)"." counter(h2)"." counter(h3)". "}
<!-- body creates counter.h1, sets it to 0 -->
<div class="test"> <!-- Inherits counter.h1 from parent -->
<h1>Heading 1 <!-- Again inherits counter.h1 from parent, creates counter.h2 -->
<!-- ::before increments counter.h1 to 1 and display value-->
</h1>
</div>
<p>Paragraph</p>
<h2>Heading 2 <!-- Inherits counter.h1 as it is from parent but not counter.h2, creates counter.h3 -->
<!-- ::before has no counter.h2, so creates a counter.h2 and increments to 1 -->
</h2>
<p>Paragraph</p>
<h3>Heading 3 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2 -->
<!-- ::before inherits counter.h3 from parent and increments to 1, has no counter.h2 so creates a new counter.h2 and sets to 0 -->
</h3>
<p>Paragraph</p>
<h3>2nd Heading 3 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2 -->
<!-- ::before inherits counter.h3 from parent and increments to 2, has no counter.h2 so creates a new counter.h2 and sets to 0 -->
</h3>
<p>Paragraph</p>
<h2>2nd Heading 2 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2, resets counter.h3 to 0 -->
<!-- ::before has no counter.h2, so creates a counter.h2 and increments to 1 -->
</h2>
<p>Paragraph</p>
<h2>3rd Heading 2 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2, resets counter.h3 to 0 -->
<!-- ::before has no counter.h2, so creates a counter.h2 and increments to 1 -->
</h2>
<p>Paragraph</p>
<h1>2nd Heading 1 <!-- Inherits counter.h1 as it is from parent, couunter.h3 from sibling but not counter.h2, resets counter.h2 to 0 -->
<!-- ::before inherits counter.h1 from parent and increments to 2 -->
</h1>
Ideal solution to this problem would be to reset all 3 counters first at body itself so that all elements are aware of the existence of a counter and can inherit or use its value.
body {counter-reset: h1 h2 h3}
h1 {counter-reset: h2 h3}
h2 {counter-reset: h3}
h1:before {counter-increment: h1; content: counter(h1)". "}
h2:before {counter-increment: h2; content: counter(h1)"." counter(h2)". "}
h3:before {counter-increment: h3; content: counter(h1)"." counter(h2)"." counter(h3)". "}
<!-- body creates counter.h1, counter.h2, counter.h3 sets all 0 -->
<div class="test"> <!-- Inherits all 3 counters -->
<h1>Heading 1 <!-- Inherits all 3 counters, resets counter.h2 and counter.h3 to 0 -->
<!-- ::before also inherits all 3 counters, increments counter.h1 to 1 and displays value -->
</h1>
</div>
<p>Paragraph</p>
<h2>Heading 2 <!-- Inherits all 3 counters, resets counter.h3 to 0 -->
<!-- ::before also inherits all 3 counters, increments counter.h2 to 1 and displays value -->
</h2>
<p>Paragraph</p>
<h3>Heading 3 <!-- Inherits all 3 counters -->
<!-- ::before also inherits all 3 counters, increments counter.h3 to 1 and displays value -->
</h3>
<p>Paragraph</p>
<h3>2nd Heading 3 <!-- Inherits all 3 counters -->
<!-- ::before also inherits all 3 counters, increments counter.h3 to 2 and displays value -->
</h3>
<p>Paragraph</p>
<h2>2nd Heading 2 <!-- Inherits all 3 counters, resets counter.h3 to 0 -->
<!-- ::before also inherits all 3 counters, increments counter.h2 to 2, resets counter.h3 to 0 and displays value -->
</h2>
<p>Paragraph</p>
<h2>3rd Heading 2 <!-- Inherits all 3 counters, resets counter.h3 to 0 -->
<!-- ::before also inherits all 3 counters, increments counter.h2 to 3, resets counter.h3 to 0 and displays value -->
</h2>
<p>Paragraph</p>
<h1>2nd Heading 1 <!-- Inherits all 3 counters, resets counter.h2 and counter.h3 to 0 -->
<!-- ::before also inherits all 3 counters, increments counter.h1 to 2, resets counter.h2, counter.h3 to 0 and displays value -->
</h1>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With