The counter-reset you have used at
<div><p class="numlist reset" >first text</p></div>
does not reset the original counter as expected. Instead of resetting the existing counter, a new counter with the same name is created within the scope of the P element and any subsequent siblings or children.
To illustrate this, consider replacing counter(standard)
with "counters(standard," AND ")
:
.body {
counter-reset: standard inline;
}
div > p.numlist::before {
counter-increment: standard;
content: counters(standard," AND ") ". ";
}
div > p.numlist.depth::before {
counter-increment: inline;
content: counter(inline) ". ";
margin-left: 50px;
}
.should-reset {
color: red;
}
div > p.numlist.reset {
counter-reset: standard;
}
<div class="body">
<div>
<p class="numlist" >first text</p>
</div>
<div>
<p class="numlist">second text</p>
</div>
<div>
<p class="numlist">third text</p>
</div>
<!-- Only here for only here in demonstrative purpose -->
<div class="should-reset">
<p>
Start a new counter for the inlines
</p>
</div>
<div>
<p class="numlist depth" depth>first text</p>
</div>
<div>
<p class="numlist depth" depth>second text</p>
</div>
<div>
<p class="numlist depth" depth>third text</p>
</div>
<!-- Only here for only here in demonstrative purpose -->
<div class="should-reset">
<p>
Want to reset the standard counter
</p>
</div>
<div>
<p class="numlist reset" >first text</p>
</div>
<div>
<p class="numlist">second text</p>
</div>
<div>
<p class="numlist">third text</p>
</div>
</div>
In this scenario, the counters()
function displays all instances of counters with the given name visible within the current scope, rather than just the most locally defined one. However, a counter-reset
cannot reset instances from higher scopes.
This behavior is not a browser bug but is actually well-documented by W3C CSS Working Group. According to https://drafts.csswg.org/css-lists-3/#nested-counters:
Counters are “self-nesting”; instantiating a new counter on an element which inherited an identically-named counter from its parent creates a new counter of the same name, nested inside the existing counter. This is important for situations like lists in HTML, where lists can be nested inside lists to arbitrary depth: it would be impossible to define uniquely named counters for each level. The counter() function only retrieves the innermost counter of a given name on the element, whereas the counters() function uses all counters of a given name that contain the element.
The scope of a counter therefore starts at the first element in the document that instantiates that counter and includes the element’s descendants and its following siblings with their descendants. However, it does not include any elements in the scope of a counter with the same name created by a counter-reset on a later sibling of the element, allowing such explicit counter instantiations to obscure those earlier siblings.
If modifying the HTML directly is not an option, and the <div class="should-reset">
tags are purely informational, achieving this solely through CSS is challenging. A pseudo-class like :has() would be required, such as:
div:has(> p.numlist.reset) {
counter-reset: standard;
}
However, as of now, the :has()
pseudo-class is not supported in major browsers due to performance concerns. Even if implemented, it would create a nested counter instead of resetting the original counter.
In conclusion, the issue you are facing with counter-reset is not a bug in browsers but a part of the specified behavior documented by the W3C CSS Working Group.