-
Notifications
You must be signed in to change notification settings - Fork 715
[css-lists] CSS counter scope/inheritance is incompatible with HTML ordinals #5477
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Slightly nervous about this one. Can I propose a fourth option which might be lower impact?
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 |
w3c/csswg-drafts#5477 Differential Revision: https://phabricator.services.mozilla.com/D87991 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1548753 gecko-commit: 75559571662961f502e2f424cc3b2d7572c50bb5 gecko-reviewers: emilio
…ibling's scope. r=emilio w3c/csswg-drafts#5477 Differential Revision: https://phabricator.services.mozilla.com/D87991
w3c/csswg-drafts#5477 Differential Revision: https://phabricator.services.mozilla.com/D87991 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1548753 gecko-commit: 75559571662961f502e2f424cc3b2d7572c50bb5 gecko-reviewers: emilio
@faceless2 If |
I've just worked through it again. I'm wrong and you're correct. Scratch that idea, sorry! |
…ibling's scope. r=emilio w3c/csswg-drafts#5477 Differential Revision: https://phabricator.services.mozilla.com/D87991
The CSS Working Group just discussed
The full IRC log of that discussion<emilio> Topic: [css-lists] CSS counter scope/inheritance is incompatible with HTML ordinals<emilio> github: https://github.com//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) |
…ng if the counter doesn't exist on the parent, per CSSWG resolution. #5477
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:
So, for the following case (no increment), for example:
According to the algorithm, If my interpretation is correct, the second inner div will only inherit it's parent's counters named
But browsers renders this as:
|
@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 |
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 (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.) |
The CSS Working Group just discussed
The full IRC log of that discussion<dael> TabAtkins: A little while ago...several years...we talked about what changes to make to the counter scoping algo to make it workable as a mech to explain html lists<dael> TabAtkins: html lists have weird behaviors for legacy reasons. I tried to write a fix that fixed what's in the thread but there's close behavior it did not solve. A related change that would fix both is define a counter has an associated scope, wide or narro. Default is wide where it's visible to children and following siblings until scope of same name is declared. Narrow is only visible to children <dael> TabAtkins: That matched how counters. You have an ol and outside of that you have an li, today b/c wide scoping the li sees the counter scope from the ol and will increment that. <dael> TabAtkins: There's some reasonable cases that are less intuitive due to wide. <dael> TabAtkins: Ability to declare scope to be narrow fixes this properly. It will be somewhat magic same way list item counter is. Will be slightly more reasonable for authors where they intent it to number a list among children <dael> TabAtkins: Concept also carried to when thinking about toggles. Having wide and narrow was necessary there. I think it's proved out that is useful. <dael> TabAtkins: Precise mechanics I have not figured out. happy to take a resolution to figure out <dael> florian: Wide is default and narrow is opt-in to match html? <dael> TabAtkins: Correct <dael> astearns: Other questions or opinions? <dael> astearns: First thing would be revert previous? <dael> astearns: Prop: Revert the previous resolution and the associated edits <dael> astearns: Obj? <dael> RESOLVED: Revert the previous resolution and the associated edits <TabAtkins> valid markup that gets weird currently is in https://github.com//issues/9076 <dael> astearns: Prop: The working group is interested in defining an opt-in narrow scope for counter resets. Exact syntax tbd <dael> TabAtkins: I expect it'll work same as reverse counter specs, but I haven't dug in enough to be certain <dael> astearns: Obj? <dael> florian: Question- you mentioned html has weird edge case. narrow scope seems too clean to cover. Do we end up matching html or is there a bajillion corner cases where we're different? <dael> TabAtkins: I think this brings us all the way or very very close enough that browsers could call it good. I know wide behavior is web breaking if applied to html counters <dael> florian: We'll discover it soon enough. We create narrow and if it doesn't work people will tell us <dael> TabAtkins: I think remaining weird was list item counter and we resolved how to handle that. Where if you don't declare on an ol it happens. I'm not completely loaded on this and it's complex <dael> RESOLVED: The working group is interested in defining an opt-in narrow scope for counter resets. Exact syntax tbd <dael> TabAtkins: 9076 was also this as well. It was the same case |
Now Firefox follows the spec change, but but not consistently. I declared a nested counter on a span, and it was inherited to a subsequent ::after Element. When I declare the nested counter on a li element, Firefox isolates it, but Chrome inherits it to the next item. So Chrome doesn't respect the Spec change at all, and Firefox does it partially. Compare Chrome and Firefox in this JSFiddle. That's really confusing. |
The last resolution was to revert the previous spec change. So Chrome is right, and if you want to isolate the nested counter you will need #9076 |
A WPT change regarding this behavior was proposed here: https://chromium-review.googlesource.com/c/chromium/src/+/5661343 The WPTs here are not yet interoperable: https://wpt.fyi/results/html/semantics/grouping-content/the-li-element?label=master&label=experimental&aligned&q=html%2Fsemantics%2Fgrouping-content Can someone confirm whether the chromium/webkit or firefox rendering of this is correct? I'm not sure based on the thread of reversing the resolution here, and this doesn't seem to match up perfectly to the example in the OP. <style>
body { margin-left: 40px }
li { list-style-type: decimal }
</style>
<li></li>
<li></li>
<li></li>
<li></li>
<div>
<li></li>
</div>
<div>
<div>
<li></li>
</div>
</div> |
I would say that Firefox is correct, because the That should be the case regardless of Mats' original proposal. |
According to HTML Standard, |
That's an HTML concept that seems only relevant for non-CSS UAs. CSS UAs need to obey https://drafts.csswg.org/css-lists/#content-property, so in this case the text comes from the |
@Loirooriol This test case is failed on Firefox. Is Firefox's behavior correct based on the above description? <style>
li {
list-style-type: decimal;
list-style-position: inside;
}
.container {
padding: 50px;
}
</style>
<div class="container">
<li>A</li>
<li>B</li>
<div>
<li>C</li>
<span>
<li>D</li>
</span>
</div>
<blockquote>
<li>E</li>
</blockquote>
<li>F</li>
</div> |
Yes, I would again say that Firefox seems right since that's how CSS counters behave, and Blink agrees with |
@Loirooriol Is the behavior of this test correct in Firefox? <style>
li {
list-style-type: decimal;
}
</style>
<div>
<li></li>
<li></li>
</div>
<div>
<li></li>
<li></li>
</div> |
Yes, Firefox is correct. The 1st |
Is this the same issue? https://issues.chromium.org/issues/359623686 |
I think so. I encountered this problem when testing a stylesheet that uses <style>
section {
counter-increment: section;
margin-inline-start: 1em;
}
section:first-of-type {
counter-reset: section;
}
section > :is(h1,h2,h3,h4,h5,h6):first-child::before {
content: counters(section, ".") " ";
}
</style>
<section>
<h1>Section Level 1</h1>
<section>
<h2>Section Level 2</h2>
</section>
<section>
<h2>Section Level 2, 2nd</h2>
<section>
<h3>Section Level 3</h3>
</section>
<section>
<h3>Section Level 3, 2nd</h3>
</section>
<section>
<h3>Section Level 3, 3rd</h3>
</section>
</section>
<section>
<h2>Section Level 2, 3rd</h2>
</section>
</section>
<section>
<h1>Section Level 1, 2nd</h1>
</section> (CodePen: https://codepen.io/MurakamiShinyu/pen/KKjZVbR ) I was surprised that the latest Chrome (126 and later) does not work as expected, while Firefox and Safari work as expected, and I thought it is a bug in Chromium. Then I found this CSS issue. I believe that reverting the spec change is the right decision, and I hope that all browsers will behave consistently. |
According to recent changes around counter inheritance in the spec:
But Example 22 in the spec conflicts with the spec. In the example, the last
A comparable issue: #10491 IMO, we need to update the spec to clarify the behavior. |
These changes need to be reverted as resolved in #5477 (comment) |
As we have reverted the spec, so the test results of Firefox and Safari are correct? <style type="text/css">
#test { counter-reset: c; }
#test span { counter-increment: c; }
#test span::before { content: counter(c, decimal-leading-zero); }
</style>
<p>The following two lines should look the same:</p>
<div id="test">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span style="counter-reset: c 98"></span>
<span></span>
<span></span>
</div> Chrome inherits from the parent element:
Firefox and Safari inherit from the sibling element:
|
Yes, but Firefox seems to have a special behavior for |
Yeah, I changed that in https://bugzilla.mozilla.org/show_bug.cgi?id=1885842 because we kept getting issues like that. |
…ibling's scope. r=emilio w3c/csswg-drafts#5477 Differential Revision: https://phabricator.services.mozilla.com/D87991
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-inlist-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:
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 thatexecCommand('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:
Con: breaks existing (author-specified) nested CSS counters of the same name
list-item
counter onlyCon: makes the built-in
list-item
and other CSS counters behave differently which is a more complicated model to implement, specify, and teach to authors(e.g. something like
ol, ul, menu { counter-reset: strict-scope(list-item); }
in the UA sheet)Con: a more complicated model to implement, specify, and teach to authors
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:
which currently renders as:


to instead render as:
which makes more sense IMO.
CC @fantasai @emilio
The text was updated successfully, but these errors were encountered: