csswg-drafts
csswg-drafts copied to clipboard
[css-flexbox] Change content-size suggestion to min-intrinsic instead of min-content?
https://drafts.csswg.org/css-flexbox/#min-size-auto
This issue stems from an interop problem discussed in https://github.com/web-platform-tests/wpt/commit/21a7c47ad593720b0fed693390884bf8570a8d0c .
In the example below, the spec dictates a final width of the flex item of 50px. But when the same element is a block box it has width 100px. Should they be different?
<div style="display: flex;">
<!-- Chrome and spec say final width is 50px. Firefox says 100px. -->
<div style="background: blue; height: 100px; aspect-ratio: 1/2; ">
<div style="width: 100px;"></div>
</div>
</div>
<!-- Everyone agrees final width is 100px -->
<div style="background: blue; height: 100px; aspect-ratio: 1/2; ">
<div style="width: 100px;"></div>
</div>
https://jsfiddle.net/dgrogan/2734sdfr/
Of course a flex item can have a different final size than an otherwise-identical block box because the whole point of a flex container is that it flexes the items. But this item is not flexed, and it's still a different size. That seems weird.
In more detail, the difference in this case is a result of aspect-ratio's automatic minimum size being more aggressive than flexbox's. Giving flex a weaker set of constraints makes sense, because we want to give flexbox the power to flex its items. But it is puzzlement-inducing that putting a no-op flex container around an element changes the element's size.
Possible solution if we want the boxes to be the same width whether they are block boxes or unflexed flex items (i.e. Firefox's behavior today):
- change content-size suggestion to be min-intrinsic[1] instead of min-content (@bfgeek previously floated this idea In https://github.com/w3c/csswg-drafts/issues/5032#issuecomment-644517090)
- Then we'd also have to change specified size suggestion to only account for computed main size properties, not preferred sizes that come from the aspect-ratio. As is, specified size suggestion is 50px, so even we did (1) and only (1), the final width of the item would still be 50px.
Or, do whatever Firefox is doing, which is probably not those.
But, if giving the blue box different sizes in the two layout modes doesn't strike anyone else as weird, then maybe we just close this issue and discard the idea of making content-size suggestion = min-intrinsic. Even if we do that, we still need to determine which of Firefox and Chrome behavior is correct.
[1] or whatever the name is, vis-a-vis https://github.com/w3c/csswg-drafts/issues/5305
Looks like Gecko does something like
content-size suggestion = max(min-content, min-intrinsic)
or maybe Gecko floors the entire automatic minimum size?
min-size:auto = max(min-size:auto, min-intrinsic)
Seems reasonable and Blink can try to match if that's the behavior we end up adopting.
@dholbert @aethanyc , can you report what logic Gecko follows such that the flex item in https://jsfiddle.net/dgrogan/2734sdfr/ has automatic minimum width of 100px?
For the flex item in https://jsfiddle.net/dgrogan/2734sdfr/, Firefox only has content size suggestion, which follows the same logic described in https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum, i.e.
max(blue background div's height 100px * (1/2), blue background's child width 100px) = 100px
Firefox currently only applies specified size suggestion only if there's a main size property. However, the current spec implies that the specified size suggestion is the item’s preferred main size, which can be computed via aspect-ratio + definite cross-size. @dholbert pointed to me that the definition was changed after the edit in https://github.com/w3c/csswg-drafts/commit/0c1a35dd5d938c9d6e5d11cd144f5f45c4460d4a, and this seems changing the behavior.
Oh, y'all apply aspect-ratio's automatic minimum size on top of flex's. Maybe Blink should match.
Blink matches Gecko about when to apply specified side suggestion.
https://drafts.csswg.org/css-flexbox-1/#min-size-auto gives one definition of automatic minimum sizing. https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum gives another. They don't always agree.
@tabatkins @fantasai , what do we do in the case of a flex item with an aspect ratio? Apply both minimums?
Chrome only applies flexbox's. I think Firefox applies both.
The underlying behavior difference may explain why firefox and chrome have different renderings for the example below.
<div style="display: flex; flex-direction: column; height: 0px;">
<div style="aspect-ratio: 1/1; width: 100px; border: 5px solid orange;">
<div style="height: 200%; background: blue;"></div>
</div>
</div>
Chrome 99 canary gives 0 height to both orange item and blue child. Firefox 95a1 gives 200px height to orange item and 400px height to blue child.
The CSS Working Group just discussed [css-flexbox] Change content-size suggestion to min-intrinsic instead of min-content?.
The full IRC log of that discussion
<emeyer> Topic: [css-flexbox] Change content-size suggestion to min-intrinsic instead of min-content?<emeyer> github: https://github.com/w3c/csswg-drafts/issues/6794
<emeyer> fantasai: I think I need to go back to read the flexbox specs from the very beginning to figure out what I think should happen here.
<emeyer> …I think we have to decide what behavior we want here and how to achieve that.
<emeyer> …I’m not sure I’m clear on any of that.
<emeyer> TabAtkins: Same here. This is important and VERY difficult to reason about correctly, and we need more time.
<emeyer> dgrogan: Base issue is that aspect-ratio define sizing one way and flex defines it another
<emeyer> …and they conflict when you aspect-ratio a flex item.
<emeyer> TabAtkins: That’s what I understand. I don’t know how to resolve that yet.
<emeyer> dgrogan: Before we start talking about changing the spec, should I change Chrome to match Firefox where they apply both minimums?
<emeyer> TabAtkins: Wouldn’t that answer the question?
<emeyer> …Because if you change to match Firefox, then the spec will just match whetever you do.
<emeyer> dgrogan: Okay, let’s pinch this off now.
<emeyer> astearns: Will remove Agenda+ and will put it back once fantasai and tabatkins have time.
<emeyer> iank_: Can we do this quickly? It’s a major problem.
<emeyer> TabAtkins: That’s the goal.
<emeyer> astearns: Let’s wait on this for now.
@tabatkins and I think some of the confusion here comes from missing a small nuance in this paragraph:
The content-based minimum size of a flex item is the smaller of its specified size suggestion and its content size suggestion if its specified size suggestion exists; otherwise, the smaller of its transferred size suggestion and its content size suggestion if the element is replaced and its transferred size suggestion exists; otherwise its content size suggestion.
The flex item in question does not have a specified size suggestion, and is not replaced, and therefore it falls through to the final clause and uses its content size suggestion which is its min-content size in the main axis (100px). Therefore Firefox's behavior here is correct.
@aethanyc mentioned
However, the current spec implies that the specified size suggestion is the item’s preferred main size, which can be computed via aspect-ratio + definite cross-size. @dholbert pointed to me that the definition was changed after the edit in 0c1a35d, and this seems changing the behavior.
0c1a35d was definitely not meant to change behavior, but I can see how switching the emphasis from the “computed value” would change how automatic sizes are interpreted. We need to clarify that we're only considering non-automatic definite sizes:
diff --git a/css-flexbox-1/Overview.bs b/css-flexbox-1/Overview.bs
index 2c3418beb..358740409 100644
--- a/css-flexbox-1/Overview.bs
+++ b/css-flexbox-1/Overview.bs
@@ -1001,7 +1001,7 @@ Grid doesn't have similarly meaningful shrinkability, so it doesn't need to care
<dl>
<dt><dfn>specified size suggestion</dfn>
<dd>
- If the item’s [=preferred size|preferred=] [=main size=] is <a>definite</a>,
+ If the item’s [=preferred size|preferred=] [=main size=] is <a>definite</a> and not [=automatic size|automatic=],
then the <a>specified size suggestion</a> is that size.
It is otherwise undefined.
Committed in ca4dc9e0a .
In https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1005344637, @dgrogan brought up the following example:
<div style="display: flex; flex-direction: column; height: 0px;">
<div style="aspect-ratio: 1/1; width: 100px; border: 5px solid orange;">
<div style="height: 200%; background: blue;"></div>
</div>
</div>
Chrome's behavior here is correct. The min-content contribution of the blue box is zero due to the cyclic percentage size rules in https://www.w3.org/TR/css-sizing-3/#cyclic-percentage-contribution. So the flex base size is 100px (from the transferred width), and the automatic minimum size is zero, resulting in a 100px hypothetical main size.
Then, since the flex container is 0px tall and the item is flexible, it shrinks down to its minimum size (0px). The blue box's percentage then resolves against that zero during layout, so the blue box is also zero.
Firefox renders this with a 200px tall orange box, and a 400px tall blue box, which means in their implementation the percentage is looping and self-applying, and just happens to be cut off on two applications. This is because they are not applying the cyclic percentage rules while calculating the orange box's automatic minimum height: they are allowing the blue box's percentage to resolve against the orange box's 100px automatic height, resulting in the orange box getting an automatic minimum height of 200px. The orange box then can't shrink below that, so during layout the blue box resolves its percentage against the 200px height, giving it a final height of 400px.
Propose to close as editorial / invalid. Please let us know if we need to consider anything else!
Could you explicitly say which engine, if any, renders the original case correctly?
<div style="display: flex;">
<!-- Chrome says final width is 50px. Firefox says 100px. -->
<div style="background: blue; height: 100px; aspect-ratio: 1/2; ">
<div style="width: 100px;"></div>
</div>
</div>
@davidsgrogan
The flex item in question does not have a specified size suggestion, and is not replaced, and therefore it falls through to the final clause and uses its content size suggestion which is its min-content size in the main axis (100px). Therefore Firefox's behavior here is correct.
— https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1026183265
Unless there's something we missed?
@tabatkins , one thing I'm confused about in your analysis -- you say:
So the flex base size is 100px (from the transferred width), and the automatic minimum size is zero
Why do you say the automatic minimum size is zero -- shouldn't it actually be 100px?
The flex item here should use the content-size suggestion i.e. its min-content height, per https://drafts.csswg.org/css-flexbox-1/#min-size-auto (since it doesn't have a specified size suggestion and is not replaced).
And I think its min-content height is 100px, not 0. At least, this simplified example (with just a single div that has explicit height:min-content) suggests that it is:
<!DOCTYPE html>
<div style="aspect-ratio: 1/1;
width: 100px; height: min-content;
background: blue; border: 5px solid orange">
</div>
Browsers agree that this^ div is 100px tall, which I think (?) means its height:min-content is resolving to 100px and hence that's its min-content height? So I'd think that that's what the content size suggestion should be, when resolving its automatic minimum size in Tab's analysis above.
For completeness, I'll point out that browsers also agree that the div in the other example here (the row-oriented flex container that @davidsgrogan asked about) does indeed have a 100px min-content width which (as fantasai noted) agrees with Firefox's behavior in that case. Here's a simplified example with width:min-content to demonstrate that the min-content width is indeed 100px there:
<div style="aspect-ratio: 1/2;
height: 100px; width: min-content;
background: blue; border: 5px solid orange">
<div style="width: 100px;"></div>
</div>
In this^ case, the min-content width does actually come from its content, i.e. its 100px-wide child; but if you edit the example to remove that child, then browsers also agree that the div ends up being 50px wide there instead (from the aspect-ratio and cross-axis size).
So, this seems to be further confirmation that the min-content size is indeed established by the aspect-ratio and the opposite-axis property (though it might be bigger the element contains content that is even larger).
@dholbert - That example is using the min-width: auto to size up to 100px, its not strictly that "min-content" is 100px in this case. E.g.
<div style="aspect-ratio: 1/2;
height: 100px; width: min-content; min-width: 0;
background: blue; border: 5px solid orange">
<div style="width: 100px;"></div>
</div>
In the above case all browsers agree that its 50px.
Here min-content is 50px, but with min-width: auto, we apply a minimum of the intrinsic min-size of 100px.
@bfgeek aha, thank you for clarifying that. I had forgotten that aspect-ratio had its own special min-width:auto behavior even with no flex/grid involvement.
~OK - with that clarification, I think @tabatkins' and @fantasai's notes above make sense to me.~ EDIT: still confused, see my next comment.
@dholbert - Given that clarification I think there is still a terminology issue here. E.g.
<div style="display: flex;">
<!-- Chrome says final width is 50px. Firefox says 100px. -->
<div style="background: blue; height: 100px; aspect-ratio: 1/2; ">
<div style="width: 100px;"></div>
</div>
</div>
The flex item in question does not have a specified size suggestion, and is not replaced, and therefore it falls through to the final clause and uses its content size suggestion which is its min-content size in the main axis (100px). Therefore Firefox's behavior here is correct.
In the given example (afaikt) the min-content size (given that it has an aspect-ratio) is actually 50px not 100px.
One thing that might mitigate the confusion here is to change the definition of min-content such that when we compute it we look to see if min-width: auto is present.
Ian
[retracting my "things make sense" comment]
So per @bfgeek 's example and comments, it sounds like the min-content size of an element with aspect-ratio and an opposite-axis size is defined by the aspect-ratio and the specified-size in the opposite axis (which corrects my misunderstanding in https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1027471017 ).
So, my confusion from https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1027455922 remains -- I'm not sure I agree with @tabatkins that the automatic minimum height of the flex item would be zero in Tab's analysis in https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1026183636 . I would think it should be the min-content size, which (per bfgeek's notes about how width:min-content resolves) would be determined by the aspect-ratio and the opposite-axis size.
Why do you say the automatic minimum size is zero -- shouldn't it actually be 100px?
Mea culpa, you're right. When writing that down, I tripped over the fact that (a) the blue child resolves to 0 height while calculating the automatic minimum size, and (b) the specified size suggestion shouldn't take aspect-ratio into account (we had just dropped a minor edit into there to make sure that automatic sizes couldn't contribute even if they're definite), and so forgot to think about aspect-ratio when talking about the content size suggestion, which should take that into account. You're correct that the automatic minimum size in this case is 100px.
So neither Chrome nor Firefox is quite right here. Instead, the orange item starts at 100px flex basis, isn't allowed to shrink below 100px, and the blue child then resolves its % against that, resulting in the blue box being 200px tall.
@davidsgrogan
The flex item in question does not have a specified size suggestion, and is not replaced, and therefore it falls through to the final clause and uses its content size suggestion which is its min-content size in the main axis (100px). Therefore Firefox's behavior here is correct.
Unless there's something we missed?
Sorry, I totally missed that paragraph.
But the content size suggestion is not 100px, it's 50px (as mentioned in https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1028193403).
My point from https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1000059881 still stands. Slightly reworded:
https://drafts.csswg.org/css-flexbox-1/#min-size-auto gives a definition of automatic minimum sizing for flex items. https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum gives a definition of automatic minimum sizing for aspect-ratio elements. As seen in this case, those definitions don't always agree.
So what do we do in the case of a flex item with an aspect ratio? Which minimum do we apply?
These definitions need to be modified so that they always agree (which I think is what Ian proposes in the last sentence of https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1028193403) OR if they don't agree, we need explicit instruction of which to honor (which is possibly both).
@bfgeek
In the given example (afaikt) the min-content size (given that it has an aspect-ratio) is actually 50px not 100px.
Where are you getting that from? Are you assuming this is from the aspect-ratio affecting the specified size suggestion? We made a small tweak to prevent that, specifying it only looks at non-automatic definite sizes, specifically because it was creating an unintentional conflict with the aspect-ratio auto minimum size. (And was pre-empting the other size suggestions which were intended to handle aspect ratios.) (And it was just wrong anyway, as it would made made width: auto provide a specified size suggestion even without aspect ratio, which would have been all kinds of wrong.)
OR if they don't agree, we need explicit instruction of which to honor (which is possibly both).
Yeah, we should make it clear what to do when they disagree. I suspect we want to honor the larger of the two (aka both minimums are active).
Where are you getting that from? Are you assuming this is from the aspect-ratio affecting the specified size suggestion?
I'm describing how engines derive the min-content size of a non-replaced element with an aspect-ratio - (which feeds into the content suggestion for this specific example). E.g. for this case this rectangle has a min-content size of 50px :
<div style="aspect-ratio: 1/2;
height: 100px; width: min-content; min-width: 0;
background: blue; border: 5px solid orange">
<div style="width: 100px;"></div>
</div>
The min-content size itself doesn't apply any automatic minimum sizing. (We don't read min-width when computing the min-content size). One option here is that it can! This would solve the issue.
Given that above is 50px we feed this into the content size suggestion which gives Chrome's output for the flexbox example being talked about.
Yeah, we should make it clear what to do when they disagree. I suspect we want to honor the larger of the two (aka both minimums are active).
https://github.com/w3c/csswg-drafts/issues/5268 is the related question whether aspect-ratio's automatic minimum size should be applied in both axes or just in the block axis.
@tabatkins @fantasai , could y'all look at this issue at your next workday, or before? @bfgeek gave his response to the question from @tabatkins at https://github.com/w3c/csswg-drafts/issues/6794#issuecomment-1029506240
yup, we're meeting next week :+1:
@tabatkins Any update?
Okay, after review and thought here, we think the correct action is to make Flex/Grid's auto-min-size use the "min intrinsic" size (rather than "min-content" size) for the content size suggestion. The difference between the two is that min intrinsic doesn't pay attention to the aspect ratio (natural or from the property). We believe this was the original intention of the spec - after all, the transferred size suggestion already invokes the aspect-ratio, so why should we invoke it again in the content size suggestion?
This would result in the example in the OP making the div 100px wide - it lacks a specified size, it's not replaced, so we just use its content size suggestion, which'll now be 100px. This matches the behavior for 'display: block'.
This gives us the same result as Ian's suggestion (of paying attention to "min-width: auto" when calculating min-content sizes) without the fallout of this making auto min sizes matter in more places, perhaps unintentionally. Since 'min-width' and 'max-width' can also take 'min-content' as a value, this keeps its resolution consistent across all these sizing properties.
some notes from our discussion:
Goal (of Automatic Minimum Size): Non-obtrusive minimum size to prevent overflow and bad things.
Currently specced as:
- if specified exists, smaller of that and content suggestion
- if transferred exists and is replaced, smaller of that and content suggestion
- otherwise, just use the content size suggestion
Proposal:
Define content size suggestion using min-intrinsic size (ignoring aspect-ratio), rather than min-content size (honoring aspect-ratio), since the transferred size suggestion is already doing the job of handling aspect ratio. (This was probably the original intention of the spec.)
Principles:
- If the non-replaced box is empty, behaves like a replaced element.
- If it is non-empty, 'min-size: auto' prevents overflow.
- If replaced, its natural size is less important than what it is explicitly sized to (by any author-specified size constraint).
- Subject to above constraints, we try to maintain the aspect ratio.
after all, the transferred size suggestion already invokes the aspect-ratio, so why should we invoke it again in the content size suggestion?
Well, the transferred size suggestion only applies to replaced elements so it doesn't already invoke the aspect-ratio for these non-replaced cases. So currently, the only thing that invokes the aspect-ratio for non-replaced elements is the content size suggestion.
Even with that said, I think your proposal is good, at least as far as flex is concerned (Ian might have non-flex reasons to define this behavior the way he proposed it). I think it also makes flex's automatic minimum size always equal aspect-ratio's automatic minimum size. So we don't have to define what to do when they conflict.
So currently, the only thing that invokes the aspect-ratio for non-replaced elements is the content size suggestion.
Right, our point is that we explicitly invoke aspect-ratio in the transferred size suggestion, and explicitly do not use that suggestion for non-replaced elements, so having the aspect-ratio still sneak in via the content-size suggestion seems like it's an accident.
Even with that said, I think your proposal is good, at least as far as flex is concerned (Ian might have non-flex reasons to define this behavior the way he proposed it). I think it also makes flex's automatic minimum size always equal aspect-ratio's automatic minimum size. So we don't have to define what to do when they conflict.
👍
Will content size suggestion still transfer definite min/max cross sizes through the aspect ratio? I.e. are the bold parts in the below definition to be removed or kept?
The content size suggestion is the min-content size in the main axis, clamped, if it has a preferred aspect ratio, by any definite minimum and maximum cross sizes converted through the aspect ratio.