w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 660 forks source link

[css-flexbox] Resolving flexible lengths should avoid 0/0 and infinite loops #8928

Open Loirooriol opened 1 year ago

Loirooriol commented 1 year ago

https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths can do 0/0 with

<div style="display: flex; width: 0px">
  <div style="flex: 1 1 0px; margin: 1px"></div>
</div>
  1. Determine the used flex factor.

The outer hypothetical main size is 2px, which is more that the container inner main size (0px), so we use the flex shrink factor.

  1. Each item in the flex line has a target main size, initially set to its flex base size.

That's 0px.

  1. Size inflexible items

No-op.

  1. Calculate initial free space

That's -2px.

  1. Loop: a. Check for flexible items

No-op.

b. Calculate the remaining free space

That's -2px

c. If the remaining free space is non-zero, distribute it proportional to the flex factors

We use the flex shrink factor, so

For every unfrozen item on the line, multiply its flex shrink factor by its inner flex base size, and note this as its scaled flex shrink factor. Find the ratio of the item’s scaled flex shrink factor to the sum of the scaled flex shrink factors of all unfrozen items on the line. Set the item’s target main size to its flex base size minus a fraction of the absolute value of the remaining free space proportional to the ratio.

That is, the scaled flex shrink factor is 1 * 0px = 0px. There is a single item, so the sum of the scaled flex shrink factors is 0px. Then the ratio is 0px / 0px = NaN. Then we set the target main size to 0px - 2px * NaN = NaN * 1px.

d. Fix min/max violations

No-op, the target main size is still NaN * 1px.

e. Freeze over-flexed items

The total violation is NaN * 1px - NaN * 1px = NaN * 1px. Therefore, we don't freeze any item.

f. Return to the start of this loop.

And this is an infinite cycle.

nicoburns commented 1 year ago

In Taffy we simply do not apply step c if the sum of the scaled flex shrink factors is zero. This seems to lead to the same result as Chrome and Firefox (0px x 2px outer div and 0px x 0px inner div).