Closed Bug 1706346 Opened 9 months ago Closed 2 months ago

Implement CSS Lists conter-reset: reversed(list-item) and <ol>/<ol reversed> default style per spec

Categories

(Core :: Layout: Generated Content, Lists, and Counters, defect)

defect

Tracking

()

RESOLVED FIXED
96 Branch
Tracking Status
firefox90 --- wontfix
firefox96 --- fixed

People

(Reporter: zcorpan, Assigned: MatsPalmgren_bugz)

References

Details

(Keywords: dev-doc-complete)

Attachments

(4 files)

The CSS Lists spec, with the reversed() proposal, is able to "explain" rendering of <ol> and <ol reversed> counters through presentational hints. See these spec changes:

https://github.com/whatwg/html/pull/4816
https://github.com/w3c/csswg-drafts/pull/6096

and wpt tests:

https://github.com/web-platform-tests/wpt/pull/28040
https://github.com/web-platform-tests/wpt/pull/28453

Component: Layout → Layout: Generated Content, Lists, and Counters

Mats, I see you filed https://github.com/whatwg/html/pull/4816, so you may be the best person to comment on the current status here; are the spec changes ready to be implemented?

Flags: needinfo?(mats)

I'm not Mats, but I iterated on Mats' spec PR to its current state, and I believe it's ready to be implemented. Gecko already implements parts of it.

Keywords: dev-doc-needed
Assignee: nobody → mats
Flags: needinfo?(mats)

Note to self: Investigate this error:

  1. (uncomment the last two list items in layout/reftests/counters/counter-reset-integer-range.html)
  2. load layout/reftests/counters/counter-reset-integer-range.html
  3. open devtools
  4. hover over the <span> elements in the DOM view

EDIT(2021-10-30): I found this error was caused by not clamping the value in the style system. I've fixed that in the upcoming patches...

Severity: -- → S3
Depends on: 1738520
Pushed by mpalmgren@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/b397e2d17854
part 1 - [css-lists] Style system changes to support 'reversed(<counter-name>)'.  r=emilio
https://hg.mozilla.org/integration/autoland/rev/bc45e0f44414
part 2 - [css-lists] Implement the counter value calculations for 'reversed(<counter-name>)'.  r=emilio
https://hg.mozilla.org/integration/autoland/rev/79ab32706124
part 3 - [css-lists] Remove the internal '-moz-list-reversed' CSS property that is no longer needed.  r=emilio
https://hg.mozilla.org/integration/autoland/rev/dcfdc1fc2cec
part 4 - [css-lists] Update existing tests and add a ton of new tests for 'reversed(<counter-name>)'.  r=emilio
Created web-platform-tests PR https://github.com/web-platform-tests/wpt/pull/31628 for changes under testing/web-platform/tests
Upstream PR merged by moz-wptsync-bot
Flags: in-testsuite+
Regressions: 1745506

FF96 documentation work for this can be tracked in https://github.com/mdn/content/issues/10856

Can you please confirm that this fix delivers:

  • Support for counter-reset to take a reversed counter. In effect it means that previously you might specify counter-reset: section 7; to declare a counter called section with initial value of 7, now you can use counter-reset: reversed(section) 7; to declare a reversed counter.
  • Implementation of the <ol> element reversed property using counter-reset that takes reversed(list-item) (where list-item is the default counter for list items).

Is that about right?

My assumption is that when you declare your own reversed counter with counter-reset, the counter-increment should by default decrement a counter. This is what testing shows me happens if I declare a reverse counter without any initial value: counter-reset: reversed(section);

However when I declare a reversed counter with a value like counter-reset: reversed(section) 6; the counter-increment increments. To get it to decrement I have to declare that it increments with a value of -1. This seems inconsistent. Is it expected?

My test CSS to order 3 level 2 headings is:

body {
  counter-reset: reversed(section) 5;   /* Create reverse counter called . */
}

h2::before {
  counter-increment: section -1;                   /* Increment the value of section counter by 1 */
  content: "Section " counter(section) ": ";    /* Display the word 'Section ', the value of
                                                   section counter, and a colon before the content
                                                   of each h3 */
}
Flags: needinfo?(mats)

(In reply to Hamish Willee from comment #13)

My assumption is that when you declare your own reversed counter with counter-reset, the counter-increment should by default decrement a counter. This is what testing shows me happens if I declare a reverse counter without any initial value: counter-reset: reversed(section);

That's not the case according to the current spec, right now counter-reset: reversed(section) 7 and counter-reset: section 7 are identical. I complained about this in https://github.com/w3c/csswg-drafts/issues/6231

One way to address the problem is by adding counter-increment: section step(1), which would increment 1 in normal lists, or decrement 1 in reversed lists. See https://github.com/w3c/csswg-drafts/issues/6800

... right now counter-reset: reversed(section) 7 and counter-reset: section 7 are identical.

Just for clarity: that's true for author defined counters (currently), but it does have an effect on the automatic increment value for the built-in list-item counter. E.g.

<div style="counter-reset: reversed(list-item) 7; list-style-type: decimal; margin-left: 2em">
 <li>six<li>five
</div>
Flags: needinfo?(mats)

@oriol, @mats The fact that list-item counters behave as I would expect in some ways makes things worse - because now things are inconsistent. That makes them hard to learn and hard to document.

Using step() as Oriol suggested would be much better: https://github.com/w3c/csswg-drafts/issues/6800

Thanks very much for all the information.

Another question (slightly unrelated). Why is counter-set needed, and what purpose does it serve compared to counter-reset. The spec makes them seem like pretty much synonyms other than this new support for reversed() in counter-reset.

The only obvious difference is that it looks like counter-reset always creates a new counter and counter-set only does so if one has not been defined. But I can't see why a developer working with CSS would care about that. Can you advise?

Flags: needinfo?(oriol-bugzilla)

(In reply to Hamish Willee from comment #17)

The only obvious difference is that it looks like counter-reset always creates a new counter and counter-set only does so if one has not been defined.

This.

But I can't see why a developer working with CSS would care about that. Can you advise?

Creating nested counters can be important when you have a nested structure, e.g.

<!DOCTYPE html>
<style>
:root, section section {
  counter-reset: heading;
}
section h1 {
  counter-increment: heading;
}
section h1::before {
  content: counters(heading, ".") ". ";
}
</style>
<h1>Title</h1>
<section>
  <h1>Section 1</h1>
</section>
<section>
  <h1>Section 2</h1>
  <section>
    <h1>Subsection 1</h1>
  </section>
  <section>
    <h1>Subsection 2</h1>
    <section>
      <h1>Subsubsection 1</h1>
    </section>
    <section>
      <h1>Subsubsection 2</h1>
    </section>
  </section>
</section>
<section>
  <h1>Section 3</h1>
</scriton>

You get:

Title
1. Section 1
2. Section 2
2.1. Subsection 1
2.2. Subsection 2
2.2.1. Subsubsection 1
2.2.2. Subsubsection 2
3. Section 3

But sometimes you just want to set a counter to a value, without instantiating a new one. counter-set does that.

Flags: needinfo?(oriol-bugzilla)

Thanks @Oriol

But sometimes you just want to set a counter to a value, without instantiating a new one. counter-set does that.

Yes, but why/when is "sometimes"? That's the bit I don't understand.
Would this perhaps allow you to number like this?

Title
1. Section 1
2. Section 2
      3. Subsection 1
      4. Subsection 2
          5. Subsubsection 1
          6. Subsubsection 2
7. Section 3

Sorry if this is dumb.

Well, in that case it would be better to instantiate the counter on the root, and then just use counter-increment everywhere.

A better usecase may be if you have missing items on a list:

<ol>
  <li>first</li>
  <li>second</li>
  <div>... TODO ...</div>
  <li value="5">fifth</li>
  <li>sixth</li>
</ol>

Then value=5 uses counter-set: list-item 5. If the author prefers to use their own counter instead of list-item, or for section titles instead of <li>, then counter-set is the way to go:

ol { counter-reset: c; }
li { counter-increment: c; }
li[value="5"] { counter-set: c 5 }
li::marker { content: counter(c) ". "; }

The spec says that for a reversed counter:

Instantiates a reversed counter of the given <counter-name> with a starting value of the given <integer>, or no starting value if not given.

But when I test this, I find that for both list-item and an author created counter the default starting value is the number of elements in the current nesting level - ie. making it easy to count backwards from the number of elements to one. Is that correct?

I ask because I thought my first test showed list-item working this way but not author created. New test seems to show both do.

Docs for this complete I believe. Thanks for your help. You track what changed from https://github.com/mdn/content/issues/10856

You need to log in before you can comment on or make changes to this bug.