[csswg-drafts] [css-lists] Algorithm for initial counter value in reversed list should repeat the last increment instead of the 1st one (#6797)

Loirooriol has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-lists] Algorithm for initial counter value in reversed list should repeat the last increment instead of the 1st one  ==
https://drafts.csswg.org/css-lists/#instantiating-counters

> 1. Let *num* be 0.
> 2. Let *first* be true.
> 3. For each element or pseudo-element *el* that increments or sets the same counter in the same scope:
>     1. Let *incrementNegated* be *el*’s `counter-increment` integer value for this counter, multiplied by -1.
>     2. If *first* is true, then add *incrementNegated* to *num* and set *first* to false.
>     3. If *el* sets this counter with `counter-set`, then add that integer value to *num* and break this loop.
>     4. Add *incrementNegated* to *num*.
> 4. Return *num*.

### Problem 1: the value of the last item is the increment of the 1st one.

Let's consider this basic list:

```html
<ol reversed><!-- 5 -->
  <li style="counter-increment: list-item -1"><!-- 4 --></li>
  <li style="counter-increment: list-item -1"><!-- 3 --></li>
  <li style="counter-increment: list-item -1"><!-- 2 --></li>
  <li style="counter-increment: list-item -1"><!-- 1 --></li>
</ol>
```

The initial value is 5 which is the sum of the counter-increments, with the 1st one counted twice. The result looks good.
Then, let's change one increment in the middle:

```html
<ol reversed><!-- 6 -->
  <li style="counter-increment: list-item -1"><!-- 5 --></li>
  <li style="counter-increment: list-item -1"><!-- 4 --></li>
  <li style="counter-increment: list-item -2"><!-- 2 --></li>
  <li style="counter-increment: list-item -1"><!-- 1 --></li>
</ol>
```

Only the preceding elements are affected, as expected. But now let's undo and change the first increment instead:

```html
<ol reversed><!-- 7 -->
  <li style="counter-increment: list-item -2"><!-- 5 --></li>
  <li style="counter-increment: list-item -1"><!-- 4 --></li>
  <li style="counter-increment: list-item -1"><!-- 3 --></li>
  <li style="counter-increment: list-item -1"><!-- 2 --></li>
</ol>
```

Now all the values changed! That's because, by counting the 1st increment twice, the value of the last item will precisely be the increment of the 1st item (assuming there is no `counter-set`). This doesn't seem to make much sense.

### Problem 2: `counter-set` to the current value affects preceding values

Let's consider, again,

```html
<ol reversed><!-- 6 -->
  <li style="counter-increment: list-item -1"><!-- 5 --></li>
  <li style="counter-increment: list-item -1"><!-- 4 --></li>
  <li style="counter-increment: list-item -2"><!-- 2 --></li>
  <li style="counter-increment: list-item -1"><!-- 1 --></li>
</ol>
```

and then add a `counter-set: list-item 2` to the item that already had value 2:

```html
<ol reversed><!-- 5 -->
  <li style="counter-increment: list-item -1"><!-- 4 --></li>
  <li style="counter-increment: list-item -1"><!-- 3 --></li>
  <li style="counter-increment: list-item -2; counter-set: list-item 2"><!-- 2 --></li>
  <li style="counter-increment: list-item -1"><!-- 1 --></li>
</ol>
```

Seems unexpected that when setting the counter to the same value that it would have without `counter-set`, the values of the preceding items change. Basically, instead of using the `counter-increment` of the 3rd item as the difference between the 2nd and 3rd items, it's using the counter-increment of the 1st item!

### Solution: use the last increment twice, instead of the 1st one

The algorithm should probably be more like:

1. Let `num` be 0.
2. Let `incrementNegated` be 0.
3. For each element or pseudo-element `el` that increments or sets the same counter in the same scope:
   1. Set `incrementNegated` to `el`’s `counter-increment` integer value for this counter, multiplied by -1.
   2. If `el` sets this counter with `counter-set`, then add that integer value to `num` and break this loop.
   3. Add `incrementNegated` to `num`.
4. Add `incrementNegated` to `num`.
5. Return `num`.

Or, taking #6738 into account, repeat the last non-zero increment:

1. Let `num` be 0.
2. Let `lastNonZeroIncrementNegated` be 0.
3. For each element or pseudo-element `el` that increments or sets the same counter in the same scope:
   1. Let `incrementNegated` to `el`’s `counter-increment` integer value for this counter, multiplied by -1.
   2. If `incrementNegated` is not zero, set `lastNonZeroIncrementNegated` to `incrementNegated`.
   2. If `el` sets this counter with `counter-set`, then add that integer value to `num` and break this loop.
   3. Add `incrementNegated` to `num`.
4. Add `lastNonZeroIncrementNegated` to `num`.
5. Return `num`.

Then we would have:

```html
<ol reversed><!-- 6 -->
  <li style="counter-increment: list-item -2"><!-- 4 --></li>
  <li style="counter-increment: list-item -1"><!-- 3 --></li>
  <li style="counter-increment: list-item -1"><!-- 2 --></li>
  <li style="counter-increment: list-item -1"><!-- 1 --></li>
</ol>
```

```html
<ol reversed><!-- 6 -->
  <li style="counter-increment: list-item -1"><!-- 5 --></li>
  <li style="counter-increment: list-item -1"><!-- 4 --></li>
  <li style="counter-increment: list-item -2; counter-set: list-item 2"><!-- 2 --></li>
  <li style="counter-increment: list-item -1"><!-- 1 --></li>
</ol>
```

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/6797 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 4 November 2021 19:15:37 UTC