Open davidsgrogan opened 1 year ago
cc/ @dholbert as FYI
cc/ @dholbert as FYI
(Thanks! I've been meaning to implement in Gecko as well but haven't found time to do so yet. I'll keep an eye on this & related issues.)
Status update:
There's an experimental conservative algorithm for calculating intrinsic sizes of row containers in Chrome Canary. It's been enabled at 100% installs for three weeks with virtually no issues.[^1] The goal is to establish a web-compat floor.
We don't examine flex fractions at all for intrinsic size computations. Instead, an item's final contribution is (1) its hypothetical main size IF not derived from the item's contents[^2] AND the item has a 0 flex factor in whichever direction it wants to go; otherwise: (2) same as old algorithm, which is intrinsic contribution from css-sizing-3 (notably NOT the contribution specified in css-flexbox)
This conservative algorithm is an attempt to cause the least possible compat problems. It is the smallest, most conservative change we think we can make. The downside is that it fixes only the most egregious of the old algorithm's shortcomings. If this conservative algorithm has nontrivial compat issues, we are permanently stuck with the existing algorithm. The positive flip side is that if this conservative algorithm IS web compatible, we could then try to derive a less conservative algorithm that addresses more of the old algorithm's shortcomings.
In that vein, we've collected 6 author-submitted examples of the old algorithm's shortcomings at http://wpt.live/css/css-flexbox/intrinsic-size/row-use-cases-001.html. Regressions from our previous attempts to change this algorithm are at http://wpt.live/css/css-flexbox/intrinsic-size/row-compat-001.html. The specified algorithm fixes all the use cases but fails all the compat tests. This conservative algorithm passes all the compat tests but fixes only half of the use cases.
let ComputeIntrinsicSizesOfSingleLineRowContainer = (flex_container) => {
let container_min_size, container_max_size = container_border_and_padding;
for (item in flex_container.items) {
let {min_contribution, max_contribution} = ComputeIntrinsicContributionsPerCSSSizing3(item);
const cant_move = (item.shrink_factor == 0 && item.flex_base_size > min_contribution) ||
(item.grow_factor == 0 && item.flex_base_size < min_contribution);
if (cant_move && item.basis != "content")
min_contribution = item.hypothetical_main_size;
// Analog for max, which is identical to above except s/min/max/g.
const cant_move = (item.shrink_factor == 0 && item.flex_base_size > max_contribution) ||
(item.grow_factor == 0 && item.flex_base_size < max_contribution);
if (cant_move && item.basis != "content")
max_contribution = item.hypothetical_main_size;
container_min_size += min_contribution;
container_max_size += max_contribution;
}
return { container_min_size, container_max_size };
}
[^1]: Caveat: we get many more compat reports when our changes graduate release channels, and this change has to survive 3 more graduations.
[^2]: In other words: if (the specified value of flex-basis
is definite) OR (the specified value of flex-basis
is auto
AND the specified main size is definite).
The CSS Working Group just discussed [css-flexbox] Intrinsic main size algorithm for row flexboxes not web compatible
, and agreed to the following:
RESOLVED: take existing algo, mark it as informative, and explain why that is.
RESOLVED: spec what chrome has implemented in canary currently
Blink launched an implementation of the specified intrinsic sizing algorithm on Canary for a few days. It was quite clear that the algorithm for computing the intrinsic main size for single-line row flexboxes is not web compatible.
min-content
sizes are too big. Not yet sure aboutmax-content
sizes.The existing web needs the container's
min-content
size to be100px
in the case below. But the specified algorithm gives it a width of300px
[1].[1]
chosen flex fraction == 0
. So first item's final contribution is300px + 0*0
. Second item's final contribution is0
. Their sum is the min-content width of300px
. [2] No one actually specifieswidth: min-content
. But the container'smin-content
size percolates up to ancestor flexboxes (used in automatic minimum widths) or table cells (forfit-content
sizing). The new largermin-content
sizes cause compat problems for such ancestors.We implemented a variant of the algorithm that is closer to what engines currently ship. In this variant, for containers where
chosen flex fraction <= 0
, items' final contribution to the container'smin-content
size is (1) itsflex-basis
if the item has a 0 flex factor in whichever direction it wants to go (shrink ifflex-basis > min-content
contribution, grow otherwise); otherwise: (2) itsmin-content contribution
.In local testing, this variant has proven to be significantly more web compatible than what is currently specified, but possibly still insufficiently compatible. We haven't tested it in the wild.
We've also discussed, but haven't experimented much with, another variant even closer to what engines currently ship. In this variant, we don't examine flex fractions at all for
min-content
computations. Instead, each item's final contribution is (1) flex-basis if theflex-basis
is not derived from the item's contents AND the item has a 0 flex factor in whichever direction it wants to go; otherwise: (2) itsmin-content contribution
.Both of these variants break the promise, in some cases, that an item will end up at least as large as its
min-content contribution
after the flex algorithm runs. But that seems to be necessary given where the web is today. (Also, I omitted clamping by used min/max sizes in the descriptions above, but of course they need to be accounted for.)@tabatkins @fantasai, you've thought about this algorithm a lot. Do you have ideas for variants that are more principled than our attempts, but that preserve current behavior in the reduced case presented above?
We haven't yet gotten as strong a signal on multiline row or multiline column flexboxes. Investigations ongoing.