Skip to content
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

[css-lists-3] list-item counter nesting is confusing #9076

Open
fantasai opened this issue Jul 17, 2023 · 18 comments
Open

[css-lists-3] list-item counter nesting is confusing #9076

fantasai opened this issue Jul 17, 2023 · 18 comments
Labels
css-lists-3 Current Work

Comments

@fantasai
Copy link
Collaborator

fantasai commented Jul 17, 2023

See @ZoeBijl’s thread at https://w3c.social/@moiety@front-end.social/110729923581670564

The testcase uses the following code:

<ol>
    <li>Some</li>
    <li>List</li>
    <li>Items
        <ol>
        <li>Nested</li>
        </ol>
    </li>
</ol>

<section>
    <ol>
        <li>Some</li>
        <li>List</li>
        <li>Items
            <ol>
                <li>Nested</li>
            </ol>
        </li>
    </ol>
</section>

<ol>
    <li>Some</li>
    <li>List
        <ol>
            <li>Nested</li>
        </ol>
    </li>
    <li>Items
    </li>
</ol>

which, if rendered with counters(list-item, "."), results in what looks like nonsense:

1. Some
2. List
3. Items
    3.1. Nested

3.1 Some
3.2 List
3.3 Items
    3.3.1. Nested

1. Some
2. List
    2.1. Nested
3. Items

This is apparently per spec. I'm not sure how to fix it, but we should probably fix it... it might require some new feature that adjusts counter scoping.

@fantasai fantasai added the css-lists-3 Current Work label Jul 17, 2023
@dbaron
Copy link
Member

dbaron commented Jul 18, 2023

Maybe we should introduce the concept of "narrow" versus "wide" scope to counters, where narrow means element + descendants, and wide means element + later siblings + descendants of all. Counters currently use wide scope, but lists would be better served by narrow scope. (This concept is explicit in the CSS Toggles proposal and probably in other things.)

Counters were designed to try to handle both lists and headers (h1...h6)... and the original spec had some errors. When I initially implemented in in Gecko, I proposed fixes for the errors in a way that would make the key use cases work, but in hindsight it would have been better to propose bigger structural changes rather than the minimal thing to turn the then-current spec draft into something that actually rendered its examples as promised.

@Loirooriol
Copy link
Contributor

I think narrow scoped counters would also allow fixing #5477 in a proper way, and I support that.

@Loirooriol
Copy link
Contributor

Just want to note that there are old sites relying on the "nonsense" (expecting that counter-reset will propagate to following siblings). That's because we didn't have counter-set in the past, so people made do with counter-reset. So changing the current behavior doesn't seem possible due to compat, would need to be something new like counter-reset: scoped(counter-name) 5

@tabatkins
Copy link
Member

Yeah this is definitely not changeable by default, counters must have wide scope. But making it narrow scope optionally is a good idea!

@mirisuzanne
Copy link
Contributor

Might it be possible to change the default only for the special list-item counter, which is a much more recent addition? I don't believe this is how list item counters have worked historically.

@tabatkins
Copy link
Member

I think historically it wasn't possible to tell what the behavior was, since you couldn't refer to the list-item counter for counters(). (The behavior is unobservable if you're just looking at the value of the innermost counter for a given name.)

But yeah it is likely possible to change the HTML default.

@Loirooriol
Copy link
Contributor

Yeah, the UA stylesheet has something like ol, ul { counter-reset: list-item }. It's hopefully fine to upgrade this to ol, ul { counter-reset: sane-scope(list-item) }, what can't change is the behavior of counter-reset: list-item.

@Loirooriol
Copy link
Contributor

Just noting that this isn't only for counters(), basic HTML lists also have oddities as currently defined (since #5477 was not a comprehensive solution):

<ol>
    <li>Some</li>
    <li>List</li>
    <li>Items
        <ol>
            <li>Nested</li>
        </ol>
    </li>
</ol>
<section style="list-style-type: decimal">
    <li>Some</li>
    <li>List</li>
    <li>Items
        <ol>
            <li>Nested</li>
        </ol>
    </li>
</section>
<ol>
    <li>Some</li>
    <li>List
        <ol>
            <li>Nested</li>
        </ol>
    </li>
    <li>Items</li>
</ol>

Blink and WebKit don't use actual counters, so they show the more reasonable

1. Some
2. List
3. Items
    1. Nested

1 Some
2 List
3 Items
    1. Nested

1. Some
2. List
    1. Nested
3. Items

But in Firefox, or when manually switching to an actual counter,

1. Some
2. List
3. Items
    1. Nested

4 Some
5 List
6 Items
    1. Nested

1. Some
2. List
    1. Nested
3. Items

@Loirooriol
Copy link
Contributor

I guess we will need 2 variants of narrow-scoped counters: normal and reversed. scoped() and scoped-reversed()?

@tabatkins
Copy link
Member

Something like that, yes.

@Loirooriol
Copy link
Contributor

I guess the basic idea would be that counters would have a bool to track if they are narrow-scoped. Then, counter inheritance would skip counters from the preceding sibling which are narrow-scoped and whose creator is the preceding sibling.

What I'm less sure about is whether we want to preserve this behavior of HTML ordinals in Blink:

<div style="list-style: decimal; padding-left: 40px">
  <li></li>
  <li></li>
  <ol>
    <li></li>
    <li></li>
    <li></li>
  </ol>
  <li></li>
  <li></li>
</div>
1.
2.
    1.
    2.
    3.
3.
4.

If so, when skipping a counter as described above, would need to iterate the previous siblings until finding one which either doesn't have a counter with that name, or doesn't have the narrow-scoped flag, or the creator is an ancestor.

But it may be fine to produce

1.
2.
    1.
    2.
    3.
1.
2.

and just require instantiating the counter on the parent for the earlier behavior (like using <ol> instead of <div>).

@astearns
Copy link
Member

astearns commented Dec 7, 2023

See discussion in #5477 (comment)

@astearns astearns removed the Agenda+ label Dec 7, 2023
@Loirooriol
Copy link
Contributor

Remaining details to decide:

  • Name: scoped(), narrow-scoped()?
  • Combination with reversed(): another function like scoped-reversed() or nesting scoped(reversed())
  • If there is a non-scoped counter with the same name whose creator is an earlier sibling,
    1. Whether scoped() instantiates a new counter in addition to or in place of the earlier one.
      Maybe "in place of", like when instantiating non-scoped counters, but this can impact later siblings...
    2. If "in place of", whether later siblings can still inherit the earlier counter or not.
      Not inheriting seems simpler, but inheriting is maybe a bit better and matches HTML ordinals in Blink and WebKit.

@astearns astearns added this to Unsorted regular in Feb 2024 Agenda Feb 8, 2024
@fantasai
Copy link
Collaborator Author

fantasai commented Mar 5, 2024

I think instead of making new function types, it might be better to introduce an additional property e.g. counter-scope: [ narrow | wide ]# or something like that?

@Loirooriol
Copy link
Contributor

HTML ordinals should use narrow scopes. If there is a single property controlling the scope of all counters, it can break websites if they are using their own counters on lists.

@Loirooriol
Copy link
Contributor

Loirooriol commented Mar 7, 2024

Well, I guess we could avoid the risk by saying that a counter is narrow-scoped if its creator has counter-scope: narrow or if its name is list-item. This would make list-item more magical, but it would be fine.

@fantasai
Copy link
Collaborator Author

Alternate keywords: counter-scope: contain | cover where contain scopes the counter declared with counter-reset to the contents of the element (not the element itself).

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-lists-3] list-item counter nesting is confusing.

The full IRC log of that discussion <keithamus> oriol: something discussed in December. narrow counters
<keithamus> oriol: still propagated to descendents, not to following siblings
<keithamus> oriol: agreed to have something like this in December. Details weren't resolved. Let's do that now
<keithamus> oriol: 1. Syntax to enable this
<keithamus> oriol: first idea something like reversed counters, functional notation in the counter-reset prop.
<keithamus> oriol: takes name of counter as argument
<keithamus> oriol: maybe not great. how do you handle interactions with counter thats both narrow and reversed?
<keithamus> oriol: in general narrow counters are better default. Not defaault because we didnt have counter set
<keithamus> oriol: maybe just better to have option to set all to narrow? fantasai proposed new property counter-scope: narrow
<keithamus> oriol: need exception for list-item counter to preserve compat with html ordinals
<keithamus> oriol: list item counter would be magical but it is alreadu
<keithamus> s/alreadu/already
<kizu> q+
<astearns> ack kizu
<keithamus> kizu: given this is obscure issue. counters with list item is not something authors know or use.
<keithamus> kizu: few years ago there was a lot of compat issues. Now its better. From what I see theres some cross browser issues still
<keithamus> kizu: can we just set default to work how we expect it to work?
<keithamus> oriol: problem is blink and webkit html ordinals arent implemented using css counters
<keithamus> oriol: according to spec it should be magical
<keithamus> oriol: firefox is doing it as counter but when this change happened found some websites breaking. Added hacky narrow counters
<keithamus> oriol: we cant change html ordinals to have wide propagation
<keithamus> oriol: some expect to be narrow
<keithamus> oriol: normal css counters have had this behavior, people rely on this.
<keithamus> oriol: eg without counter-set property people use counter-reset which they want propagated to siblings
<keithamus> oriol: conflict between these. Need to keep old behavior for counters
<keithamus> oriol: we want to allow users to be able to switch to html ordinals
<keithamus> kizu: just for counters without css counters function?
<keithamus> oriol: assuming html ordinals use magical list item counter
<keithamus> oriol: we need something that works for both cases
<miriam> q+
<keithamus> oriol: proposal with new property - counter could be narrow if list item
<emilio> q+
<keithamus> oriol: or if property is set to narrow. Allow authors to decide to opt in to html ordinals
<keithamus> oriol: preserve by default existing in all cases
<keithamus> kizu: only case is that not many cases for counters list-item. If we could make default for list types work more as expected but if not possible its okay
<astearns> ack miriam
<keithamus> miriam: curious if proposed property sets the default for all counters or just the non list item ones?
<keithamus> miriam: if you set wide does it change how list item counters work?
<keithamus> fantasai: no. counter properties dont effect list item unless named
<keithamus> fantasai: list-item counter would have narrow by default unless you explicitly set list-item counter to wide.
<keithamus> fantasai: just like conter-reset none
<astearns> ack emilio
<astearns> ack dbaron
<emilio> q-
<keithamus> astearns: we're at time. Can we take back to issue?
<keithamus> astearns: make async resolution?
<dbaron> I wanted to say 2 things:
<dbaron> 1. the reason compat is interesting here is that we had a CSS feature that was designed to be the underlying mechanism behind an HTML feature, but there was a long period of time where *both* features were implemented but without the underlying-ness. So we have compat concerns about both features separately, but we also want to make them fit together.
<dbaron> 2. I'd be interested in seeing what the proposed property looks like in a little more detail: name, values, is it inherited, what does it apply to (counters established by the element?).
<fantasai> Not inherited, applies to counters declared in counter-reset
<fantasai> just like counter-style
<dbaron> (Also, Zoom decided that my browser had denied microphone permission to it... despite that I'd talked earlier in the meeting without leaving Zoom!)
<oriol> I would prefer it to be inherited, even if that's not consistent with other counter properties
<dbaron> see, that's why I wanted to ask :-)

@astearns astearns removed the Agenda+ label Mar 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-lists-3 Current Work
Projects
Feb 2024 Agenda
Unsorted regular
Development

No branches or pull requests

7 participants