The rules for counter scope/inheritance in CSS Lists is incompatible with HTML <ol><ul><li> ordinals and is thus not web-compatible.
https://drafts.csswg.org/css-lists/#nested-counters
https://drafts.csswg.org/css-lists/#inheriting-counters
Gecko has implemented HTML <ol><ul><li> ordinals using the built-in list-item counter as per the CSS Lists spec. However, we've got many reports that this breaks existing web content to the extent that we need to ship a (non spec-compliant) fix.
Consider this simple HTML example:
<style>
li::before { content: "(list-item:" counters(list-item,'.') ")"; }
</style>
<ol>
<li></li>
<li></li>
<ol>
<li></li>
</ol>
<li></li>
</ol>
According to CSS Lists, the correct rendering is:

This is clearly not how HTML lists should work - the last item should have the ordinal 3.
Granted, the above HTML is invalid - <ol><ul> aren't allowed as a direct child of <ol><ul>, but this kind of bogus markup is rather common on the web unfortunately. It's also the DOM that execCommand('indent') produce (sigh), which affects HTML editors. So telling authors to fix their markup isn't a tenable solution.
The alternative fixes we considered were:
list-item counter onlylist-item and other CSS counters behave differently which is a more complicated model to implement, specify, and teach to authorsol, ul, menu { counter-reset: strict-scope(list-item); } in the UA sheet)We concluded that 1 is the least bad solution, so we propose to include a new step in finding the counter scope that searches an element's ancestors first, before falling back to the current steps in the spec that searches previous siblings in reverse DOM order.
This also makes author-defined counters behave more sensible - consider the analogous example:
<style>
list, item { display: block; }
list { counter-reset: foo; margin-left: 40px; }
item { counter-increment: foo; }
item::before { content: counters(foo,'.'); }
</style>
<list>
<item></item>
<item></item>
<list>
<item></item>
</list>
<item></item>
</list>
which currently renders as:

to instead render as:

which makes more sense IMO.
CC @fantasai @emilio
Slightly nervous about this one. Can I propose a fourth option which might be lower impact?
counter-reset is applied _after_ counter-increment and counter-set (it's currently applied before). Then you can cater for the invalid markup with this in a UA sheet.ol > ol { counter-increment: list-item; counter-reset: list-item }
The outer-scoped list-item will be incremented, then a new scope is created with the counter value of 1.
The only impact that would have is on elements that have both a counter-reset and counter-increment - a pointless combination as the rules are currently defined (and also one that can be searched for to see how often its used). It feels like this approach might have less unintended side-effects (and be easier to explain too).
The outer-scoped list-item will be incremented, then a new scope is created with the counter value of 1.
@faceless2 If counter-reset: list-item is applied afterwards, then the inner scope will have value 0. And if counter inheritance prefers the previous sibling over the parent, the next element will still get the value from the inner scope? I don't get how your proposal solves the problem.
I've just worked through it again. I'm wrong and you're correct. Scratch that idea, sorry!
The CSS Working Group just discussed [css-lists] CSS counter scope/inheritance is incompatible with HTML ordinals, and agreed to the following:
RESOLVED: change CSS Lists to make all CSS counters behave differently for this caseThe full IRC log of that discussion
<emilio> Topic: [css-lists] CSS counter scope/inheritance is incompatible with HTML ordinals
<emilio> github: https://github.com/w3c/csswg-drafts/issues/5477
<emilio> TabAtkins: when I was writing the counter rules I was working from css 2.1 and my testing
<emilio> ... I knew HTML <ol> didn't match CSS counters in invalid markup
<emilio> ... Gecko tried to switch to counters for CSS lists
<emilio> ... and found out that they were not web compatible
<emilio> ... see the example in the issue with a nested <ol> directly under another
<emilio> ... html renders that as you'd probably expect
<emilio> ... that's also what editors generate for some reason
<emilio> ... In order to fix it we can specify that either html is magic
<emilio> ... that the list-item counter is magic
<emilio> ... or switch counter behavior
<emilio> ... mats is going for the later
<Rossen_> q
<emilio> ... and is proposing to do an ancestor-only check and only if that fails we look for a previous sibling counter
<emilio> ... that's probably fine and would still work with the main sibling use case which is naming headers
<emilio> ... so I'm ok with making that change
<emilio> Rossen_: you're referring to the third approach in the comment?
<emilio> TabAtkins: no, number 1
<dbaron> seems like a reasonable way to fix this without breaking use of counter numbering for headers
<emilio> fantasai: if you look at the example and replace list with section and item with h1, it will end up giving a better result
<emilio> ... I'm in favor of this change
<Rossen_> ack fantasai
<emilio> ... if we can pull it of
<emilio> off
<emilio> q+
<astearns> and you’re OK with this, faceless2?
<fantasai> emilio: We actually have made this change, unsure if released yet
<fantasai> emilio: but haven't heard of any breakage
<fantasai> Rossen_: cool
<faceless2> yes. everything I had to say on the topic before was wrong :-)
<emilio> Rossen_: objections?
<fantasai> strong +1 given emilio's report :)
<emilio> RESOLVED: change CSS Lists to make all CSS counters behave differently for this case
<emilio> [... discussion about republishing CSS2 ...]
<oriol> The change is in Firefox 82, which seems it was released on 2020-10-20 (but I still don't have it)
All right, edits are in; did some editorial cleanup of the algorithm while I was in there, as the structure of the algo didn't make much sense any more.
@MatsPalmgren Mind reviewing to make sure we've caught the right nuances?
Fun fact: I raised this (on the mailing list) back in 2016! https://lists.w3.org/Archives/Public/www-style/2016Apr/0364.html
The updated inherit counters algorithm by this commit would not produce correct result in certain cases, because it makes elements not inherit a nested counter instantiated by any preceding sibling, due to step 3 of the algorithm:
Let sibling counters be the CSS counters set of element’s preceding sibling (if it has one), or an empty CSS counters set otherwise.
For each counter of sibling counters, if element counters does not already contain a counter with the same name, append a copy of counter to element counters.
So, for the following case (no increment), for example:
div::before {
content: "(" counters(foo,'.') ")";
}
<div style="counter-reset: foo">
<div style="counter-reset: foo"></div>
<div></div>
</div>
According to the algorithm, If my interpretation is correct, the second inner div will only inherit it's parent's counters named foo, but ignores the same named nested counter instantiated by the first inner div, and it would produce:
(0)
(0.0)
(0)
But browsers renders this as:
(0)
(0.0)
(0.0)
@triple-underscore That was precisely the point of the change. Sure, it's not backwards compatible, but hopefully it will be web compatible. Though it seems that Firefox already got a complaint: https://bugzilla.mozilla.org/show_bug.cgi?id=1672569
@Loirooriol
not backwards compatible, but hopefully it will be web compatible.
Ah, that is what I wanted to know.
Another way to make both backwards compatible and web compatible might be special casing for such mis-parented <ol> mentioned in the first comment to have wrapped with “anonymous list item” for the purpose of counters (effectively, the same as option 3 in the first comment), since the author's intention is clear to do so in such cases.
(Or even more, make indeed generate a list item box for such “anonymous list item” for layout purpose, similar to generate anonymous internal table boxes for table layout; of course, it might introduce another compatibility issues.)
@MatsPalmgren Can you clarify why Firefox still renders
<style>
list, item { display: block; }
list { counter-set: foo; margin-left: 40px; }
list list { counter-reset: foo; }
item { counter-increment: foo; }
item::before { content: counters(foo,'.'); }
</style>
<list>
<item></item>
<item></item>
<list>
<item></item>
</list>
<item></item>
</list>
like this

The top-level <list> instantiates the foo counter, so why does the last <item> fall back to inheriting from the previous sibling? Is this a bug or intentional?
Most helpful comment
Fun fact: I raised this (on the mailing list) back in 2016! https://lists.w3.org/Archives/Public/www-style/2016Apr/0364.html