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] Initial value of counter-increment needs to be something different from none #3686

Closed
MatsPalmgren opened this issue Feb 28, 2019 · 21 comments
Labels
css-lists-3 Current Work

Comments

@MatsPalmgren
Copy link

Background: we (Gecko) have implemented the counter-set property, the built-in list-item counter for <ol>/<li> etc, and the ::marker pseudo for rendering. This all works fine, with one exception: counter-increment should be automatically set on list items, which means its value depends on the computed value of display. This means it's impossible to implement this in the UA sheet so we "adjust" the computed value in the style engine instead. At that point though, an author-specified counter-increment:none is lost if the initial value is none.

The natural solution to this problem is to change the initial value to something else, e.g. auto, which then computes to the relevant list-item counter value on list items and to none on other elements.

(A quick resolution would be most welcome since it blocks shipping this new implementation (which fixes a bunch of decades-old HTML list counter bugs in Gecko).)

CC @emilio @fantasai

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed counter-increment initial value.

The full IRC log of that discussion <fantasai> Topic: counter-increment initial value
<emilio_> github: https://github.com//issues/3686
<fantasai> github: https://github.com//issues/3686
<emilio_> fantasai: so there's a plan to use lists use css counters for lists
<emilio_> fantasai: looks like Gecko is on the process of implementing it
<TabAtkins> Today: <ol><li>one<li style="display:block">two<li>three</ol> results in "1. one\ntwo\n2. three"
<fantasai> fantasai: They're blocked on an issue about the initial value of counter-increment
<heycam> emilio_: the issue is not that we need it to implement this behavior, but we need it to allow the author to say counter-style:none on a list
<fantasai> fantasai_: Basically by default we need to increment list-item
<heycam> s/counter-style/counter-increment/
<heycam> dbaron: and does that style go on the list item or the marker pseudo?
<heycam> emilio_: the list item
<heycam> florian: this is not just for markup lists, because if it was we can do it in the UA sheet, but it's also when you create list items through the display property
<heycam> emilio_: the computed value of counter-increment needs to depend on display
<heycam> ... it's not a huge issue
<heycam> ... we have this kind of relationship for fonts and other properties
<heycam> ... the issue is that the author specified value gets lost
<heycam> TabAtkins: sure
<heycam> dbaron: so auto would mean list item 1 if your display is list-item, and none for anything else?
<fremy> q+
<heycam> emilio_: yes
<heycam> ... and the computed value wouldn't include "auto"
<heycam> emilio_: otherwise you get into trouble with gCS, checking it against none or something
<heycam> fremy: what if on a list item currently you do counter-set: my-list-item 5
<xfq> ack fremy
<heycam> TabAtkins: counter-set or counter-increment?
<heycam> emilio_: if you set counter-increment to something else you will lose the auto increment
<heycam> ... Edge does something like this
<heycam> AmeliaBR: you have a todo list, and you're kepeing your own track of how many items in the list are completed or ont, don't want to muck up the existing list counters
<heycam> fantasai: we discussed something similar to this ~12 years ago
<heycam> ... from what I recall, the conclusion we ended up with was that the magic counter would be implied no matter what the value of the counter property was
<heycam> ... if you want to override that implied behavior, you could call it out explicitly
<heycam> ... none would not turn off increments for list-item
<heycam> ... neither would 0
<heycam> ... but 'list-item 0' would
<fremy> +1
<heycam> emilio_: ok
<dbaron> s/neither would 0/neither would 'foo 0'/
<heycam> ... then we don't need this, but we should change the spec to say that the only way you can reset list-item is this way
<heycam> TabAtkins: happy with that, then the spec doesn't have to disagree with implementations now
<TabAtkins> s/now/as much/
<heycam> Rossen: the issue about the initial value of counter-increment
<heycam> ... being something different from none
<heycam> emilio_: one annoying thing is that counter-increment is the only weirdo property that depends on display
<heycam> ... you can explain counter-set for <li value=foo> using attribute mapping
<heycam> ... if you define that to be magical and non-overridable, then it becomes more complicated to implement
<heycam> fantasai: you run into the same issue if people are using counters already and are clobbered
<heycam> emilio_: for li items inside an ol with the value attribute
<heycam> ... I'm fine restricting this solution to counter-increment
<heycam> ... or maybe counter-reset too?
<heycam> TabAtkins: we already need magic for these things because of reversed
<heycam> AmeliaBR: it sounds like in addition to having the list-item is always auto incremented unless explicitly told, we also need a way to say increment if displayed versus always increment
<heycam> emilio_: that is the magic that counter-increment needs for list-item
<heycam> ... we don't need that magic for counter-set or counter-reset for lists
<heycam> dbaron: there's one other thing that makes me uncomfrtable, but leads to an alterntaive
<heycam> ... right now if you say counter-increment: foo 1, foo 1; you increment the counter by 2
<heycam> fantasai: there's no comma
<heycam> dbaron: saying that if you say list-item at all anywhere then it overrides the implicit "list-item 1" feels weird to me
<heycam> ... another way to do it is that display:list-item implicitly have a "list-item 1" in there. but you can add "list-item -1" in there to undo that effect
<heycam> [general groans]
<TabAtkins> [collective groan]
<TabAtkins> everyone: 😭😭😭
<fantasai> emilio_: So you say display: list-item has a magic list-item 1 increment
<fantasai> emilio_: and you can specify another one to cancel it
<fantasai> dbaron: you say list-item -1
<heycam> fantasai: one of authors' goals is to expose counters to do interesting thing swith them
<heycam> ... I think this makes it very confusing
<heycam> AmeliaBR: if you hide a list item then the next one would jump down a number
<heycam> fantasai: I would rather it be an override
<heycam> dbaron: I don't understand the hiding thing
<heycam> ... it feels inconsistent that counter:foo 1 doesn't change it, but if you put list-item into that list that the other one disappears
<heycam> fremy: if you do a set and don't do the increment, it's wrong?
<heycam> ... if you have <li value=4> you do'nt increment
<heycam> ... it sets to that value
<heycam> dbaron: how you implement <li value> is another question
<AmeliaBR> if you have `counter-increment: list-item -1`, that wouldn't have the magical dependence on display. So now hidden elements would reduce your overall counter, wouldn't they?
<heycam> emilio_: the way the spec defines it is mapping the attribute to counter-set property
<heycam> ... and then to counter-increment: none too
<AmeliaBR> q+
<heycam> dbaron: if we change it this way, we have to chnage hte mapping of the value attribute to counter-increment: list-item 0
<heycam> ... to expliitly suppress the incrementing
<heycam> ... and then if the author sets some other counter, it would break their value attribute
<heycam> dbaron: if the UA sheet for <li value=5> counter-set: list-item 5; counter-increment: list-item 0; then the author sets counter-increment explicitly
<heycam> ... it would lose the 'list-item 0' counteraction
<heycam> fremy: does anybody use the value attribute?
<heycam> AmeliaBR: yes, commonly with pages of lists
<heycam> ack AmeliaBR
<heycam> AmeliaBR: has anyone thought for the issue of having the list-item counter depend on display, is that something we're ok with exposing to user counters as well?
<heycam> emilio_: no
<heycam> AmeliaBR: definitely a no?
<heycam> ... that only list-item has that?
<heycam> TabAtkins: we do have the case that counters only increment on things that have counters
<heycam> ... but that's different from what list-item wants to do, which is depend on display:list-item explicitly
<heycam> AmeliaBR: so regular counters turn off with display:none, but the list-item counter turns off for anything other than display:list-item
<heycam> TabAtkins: ye
<heycam> s/ye/yes
<TabAtkins> s/have counters/generate boxes/
<heycam> emilio_: so there are 2 proposals
<heycam> ... one is that list-item is magically appended to counter-increment for list items
<heycam> fantasai: unconditionally
<heycam> ... that's dbaron's proposal
<heycam> ... the alternative, the earlier discussed one, is that it's only added the the list-item counter is not mentioned in that list
<heycam> ... so if the author doesn't have to think about what the UA is doing
<heycam> s/if //
<heycam> fremy: I was thinking about dbaron's issue -- there is a way of extending this
<heycam> ... you could stop the magical behavior if list-item appears explicitly in any of the counter properties
<heycam> ... then you can map value="" into counter-set without worrying about counter-increment being clobbered by the author
<heycam> fantasai: I don't think you want to do that
<heycam> ... having property interactions like this makes it mor edifficult to implement
<heycam> ... we want authors to be able to manipulate the list-item counter in a straightforwad manner
<heycam> ... looking at other properties is more confusing
<heycam> ... the author wants to set the counter to something, or change hte increment, or both -- but if mentioning list-item in one changes how the other behaves, that's confusing
<heycam> fremy: <li value="5"> maps to counter-set: list-item 5; and the counter-increment won't use the implied list-item because it appears in counter-set
<heycam> fantasai: why wouldn't you have this behavior for other counters?
<dbaron> "Inheriting counters must be done before resetting counters, which must be done before setting counters, which must be done before incrementing counters, which must be done before using counters (for example, in the content property)."
<heycam> ... if it's useful we can do it for other counters
<heycam> emilio_: resets are applied before increments
<heycam> dbaron: reset, then sets, then increments
<heycam> emilio_: so the increment will always be applied unless you suppress it
<heycam> fremy: either you set the list-item value, and not do the automatica increment
<heycam> emilio_: if you do what dbaron says, you could map the li value to counter-set, then counter-increment: list-item -1
<heycam> fantasai: if we're cringing in there there will be a lot of cringing in the world
<fantasai> s/in there/in here/
<fremy> so counter-increment has "listitem 1" implied except if you "counter-set: listitem 5" or "counter-increment: listitem 0"
<heycam> TabAtkins: I suggest figuring out the technical issues in the GH issue itself
<heycam> dbaron: I think I'm OK with Elika's proposal
<heycam> ... mine has the disadvantage [...]
<heycam> AmeliaBR: I am voting for fremy's proposal
<heycam> Rossen: it sounds like the leading one for a resolution would be fantasai's
<heycam> dbaron: I will write the 3 alternatives in the issue
<heycam> emilio_: we could look at the code to understand the weirdness and report back

@dbaron
Copy link
Member

dbaron commented Feb 28, 2019

We just discussed this in the meeting (see minutes).

When evaluating options here, some cases we considered were:

  • author modifications to the list-item counter (to disable the implicit increment, or other modifications)
  • author modifications to other counters that happen to be on the same element that implicitly modifies the list-item counter
  • what the UA styles for <li value> and what (accidentally or intentionally) overrides them
  • what the behavior for <ol reversed> is

So we have three alternative proposals that take a different approach, with subtle differences, made in the following order:

(A) @fantasai's proposal: if an element has display: list-item, then the list-item counter is incremented unless the counter-increment property contains a reference to the list-item counter. (Authors can override this effect with counter-increment: list-item 0.

(B) @dbaron's proposal: if an element has display: list-item, then the list-item counter is incremented. (Authors can override this effect with counter-increment: list-item -1, unless the list is reversed, in which case it would be by 1.)

(C) @FremyCompany's proposal: if an element has display: list-item, then the list-item counter is incremented unless the counter-reset, counter-set, or counter-increment property contains a reference to the list-item counter.

I think there was probably the most support and the least objection to (A).

@faceless2
Copy link

faceless2 commented Feb 28, 2019

For what it's worth we have

li[value] {
    counter-set: list-item attr(value integer, 1);
    counter-increment: list-item 0;
}

in our default stylesheet, and this approach for working around the implied list-item increment seems to go back years, so (a) looks good to me.

Re. ol reversed, at some point I'm hoping to float an idea which at the moment looks like this:

ol[reversed] {
   counter-reset: list-item calc(attr(start integer, count(> li)) + 1);
}

the interesting bit being a count() function that counts the number of elements that match the selector it contains. This needs a bit of fleshing out first but so far, I think it's quite neat.

@MatsPalmgren
Copy link
Author

MatsPalmgren commented Feb 28, 2019

I prefer (A) since it's simpler than (C). I don't really see any benefit of (C) that warrants the added complexity.
(B) seems tricky to implement since <li value=N> would need to be mapped to counter-set:list-item N; counter-increment:list-item INC where INC is ±1 depending on the reversed attribute of the nearest ul/ol/menu ancestor, which looks difficult to compute for us at the point where we map attributes to style. Also, the final computed value will be counter-increment:list-item -1 list-item 1 in that case which looks weird.

Fwiw, I implemented (A) and it was fairly straight-forward. (<li value=N> then maps to counter-set:list-item N; counter-increment:list-item 0;, which nicely inhibits the code that adds the default increment for list items.)

@tabatkins
Copy link
Member

Thinking on this with a fresh mind, I think I'm for (A) as well: display:list-item just adds a magic list-item counter to the element iff counter-increment doesn't already mention list-item. It just seems overall simplest, with the least amount of tricky-looking hacks to "cancel out" the default increment.

@tabatkins
Copy link
Member

Put more directly, I think (A) is the closest we can get to having the default list counter be implemented via the UA stylesheet, while maintaining back-compat. When you need to interact with the list-item counter explicitly, the code you write under (A) is identical to what you'd write if list-item was just set up in the UA sheet, or in an author sheet.

I'm against (B) and (C) because they cause the code you write for list-item to be different than what you'd write for a manually-created counter. (B) has some conceptual simplicity (it acts like an "additively" cascaded value, which we've talked about in the past), but I don't think that underlying conceptual simplicity is worth the additional visible complexity.

I'm against (C) because of the action-at-a-distance. Having li[value] { counter-set: list-item attr(value integer); }, all by itself, cancel out the increment, when any author-created list counters would require adding an additional counter-increment: foo 0; to the rule, looks confusing and unexpected. This is again added visible complexity, but without even the underlying simplicity that (B) attempts to apply.

@FremyCompany
Copy link
Contributor

FWIW proposal (c) was mainly a counter-proposal to (b) but I would totally support (a) as well.

The reason behind (c) is that you can implement the [value] attribute of LI using a simple counter-set, otherwise that attribute also needs a counter-increment, and might interact negatively with other attributes. I'm not entirely convinced myself that being able to express [value=2] in pure css is worth it, but some people seemed to think so.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Initial value of counter-increment needs to be something different from none (three proposals), and agreed to the following:

  • RESOLVED: go with fantasai proposal (a) for initial value of counter increment?
The full IRC log of that discussion <dael> Topic: Initial value of counter-increment needs to be something different from none (three proposals)
<dael> github: https://github.com//issues/3686#issuecomment-468098431
<dael> TabAtkins: Discussion about what to do with initial value of counter to handle default list item. Few possibilities from F2F, but couldn't decide. dbaron helpfully wrote them.
<dael> TabAtkins: Reviewing them I believe fantasai approach is best
<dael> TabAtkins: Proposal: if an element has display list item default list item counter is incremented unless counter increment already says something about that item. If you want to pause you can set counter-incremenet list item 0 and it will work
<dael> TabAtkins: dbaron proposal is we can pretend it always adds a counter increment of 1 and you just stack them if you repeat. So if you want to pause count you would say list item -1. Cancelling out is useful for impl value attribute.
<dael> TabAtkins: I don't like that because it looks a lot more confusing. A -1 making it not incremenet is interesting. fantasai prop is most similar to UA impl list via UA styles. Still some magic but for most part it seems UA generated and you can interact with it in the same way
<dael> TabAtkins: I think we should go with fantasai prop and I can write it into the spec
<dael> rachelandrew: This is the version where if you want to set the list item to a spec value you have to explicitly say 0 incremenet on the list item?
<fantasai> Original thread on this issue , from 2007: https://lists.w3.org/Archives/Public/www-style/2007Oct/0100.html
<dael> TabAtkins: Yes if you're doing this by yourself. You use counter-set to set to a value and then set the 0. Works the same as a normal counter you define on your own
<TabAtkins> s/rachelandrew/AmeliaBR/
<dael> astearns: dbaron opinion?
<dael> dbaron: Fine with fantasai proposal
<dael> astearns: Obj to going with fantasai proposal for initial value of counter increment?
<dael> RESOLVED: go with fantasai proposal (a) for initial value of counter increment?

@emilio
Copy link
Collaborator

emilio commented Mar 26, 2019

Note that this also needs to change the li[value] rule to set counter-increment: list-item 0 rather than counter-increment: none.

@heycam
Copy link
Contributor

heycam commented Apr 3, 2019

Note that this also needs to change the li[value] rule to set counter-increment: list-item 0 rather than counter-increment: none.

Just to clarify, would that mean that with

<style>
.item { counter-increment: items 1; }
</style>
<ol>
  <li class=item>Abc
  <li class=item value=10>Def
  <li class=item>Ghi
</ol>

you would lose the UA-specified disabling of the list-item increment on the "Def" item? Or does counter-increment's definition include wording about whether there is an implicit "list-item 1", "list-item 0", or "list-item -1" in the counter-increment property, based on the value and reversed attributes on the element? If so, then I don't think we need the UA style sheet rule counter-increment: list-item 0. If not, then I'm not sure how the above example should work.

@FremyCompany
Copy link
Contributor

@heycam That was my understanding, yes. If you use value and counter-increment together, you need to specify listitem 0 to disable the auto-incrementing in your counter-increment based on the currently approved proposal, otherwise you would still get an automatic increment on top of what value specified. That wasn't the case in proposal C which took into account the presence of listitem in any of counter-set or counter-increment but the group went with proposal A instead as it appears simpler to implement.

Now of course your proposal makes a lot of sense, and we could have a special css property that would be listitem-counter-increment: <number> which defaults to 1 but is also being set with things like reversed and value; that would indeed mean value would set this rather than rely on authors not providing their own counter-increment at the same time as using the value attribute. I'm find this proposal really attractive.

ul {
    listitem-counter-increment: 1;
}
ul[reversed] {
    listitem-counter-increment: -1;
}
li[value] {
    counter-set: listitem attr(value as integer);
    listitem-counter-increment: 0;
}

Going further, we could make all UA actions on the listitem counter be based on a special propoperty, and have listitem-counter-set which would set the listitem counter except if listitem is mentioned in counter-set by the author, similar to your proposal for counter-increment but being applied to counter-set instead. That might be overkill given how rare I would expect that second case to be, but consistency is nice.

@fantasai
Copy link
Collaborator

fantasai commented Apr 5, 2019

Just for the record: #2464 (comment) links to the old WG discussions where we first worked out how the list-item counter should work.

fantasai added a commit that referenced this issue Apr 10, 2019
…rose supporting this example that we expect to work. Related to discussion in #3686 (and a number of more ancient WG discussions)
@FremyCompany
Copy link
Contributor

I think we can close this issue based on the other resolution (feel free to to reopen if you disagree).

My understanding is that your proposed auto is already the behavior of none, and listitem 0 corresponds exactly to the none value you were proposing. So adding auto and changing the meaning of none wouldn't provide any new capability to the author.

@MatsPalmgren
Copy link
Author

@FremyCompany True, but counter-increment: none is a more concise and natural syntax than counter-increment: list-item 0, IMO. But yeah, implementing the automatic increment for list items as a used-value magic thing instead of a computed value lessens the need for counter-increment: auto. I don't feel strongly either way, so used-value magic is fine with me.

@MatsPalmgren
Copy link
Author

It would be nice though if the CSSWG could be a little more precise in its resolutions. This issue has "initial value" in the subject, and the OP clearly states that we implemented it as a computed value.

The description of options and the resolution:

RESOLVED: go with fantasai proposal (a) for initial value of counter increment?

never mentions used value once. Additionally, initial value is a CSS term that implies a computed value.

This creates confusion about what the CSSWG has discussed and resolved. Confusion that has on several occasions led us (Gecko) to implement things in the wrong way and thus waste precious resources on filing spec issues, re-implement it in the right way and update tests, filing bogus bug reports on other engines etc. For an UA vendor with limited resources like Mozilla this is VERY costly. I've also seen on several occasions that CSSWG members themselves don't agree afterwards what was being discussed and/or what the resolution means.

I would suggest that you, before a resolution is made, take a minute to formulate a detailed and precise resolution statement that cannot be misinterpreted. In particular, when the word "value" appears in the resolution, make sure you always qualify every occurrence as a specified, computed, resolved or used value. Thanks.

@FremyCompany
Copy link
Contributor

@MatsPalmgren Sure, but it's not like we are imprecise on purpose, it's just that when you just discussed something it appears clear in your head.

@wis

This comment has been minimized.

@faceless2

This comment has been minimized.

@wis

This comment has been minimized.

@dbaron

This comment has been minimized.

@faceless2

This comment has been minimized.

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
None yet
Development

No branches or pull requests