Repository navigation
[css-flexbox-1] Inconsistent sizing of replaced elements in flex containers #12012
Description
Context:
Consider the following flex layout:
<!DOCTYPE html>
<div style="display: flex; max-width: 500px; font-family: Arial;">
<div>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque, vitae? Recusandae porro eveniet sapiente placeat magnam enim fugit provident, numquam vero ducimus minus iusto ullam aliquam...
</div>
<img src="box.jpg" alt="box" style="width: 0; min-width: 50%" />
</div>In this case, flex-basis is initially auto, which causes it to use the width property. Since width: 0 is specified, that becomes the initial flex base size. However, due to min-width: 50%, this base size is adjusted up to the hypothetical main size of 250px. Once the flex item’s main size is resolved, the cross size is determined by laying out the item as if it were an in-flow block-level box. Finally, the cross size is stretched to match the flex line’s used cross size, as expected.
Both Chrome and Firefox render the image at 250px wide. The image's natural size is 200x200.
Now consider this modified version:
<!DOCTYPE html>
<div style="display: flex; max-width: 500px; font-family: Arial;">
<div>
Lorem ipsum...
</div>
<img src="box.jpg" alt="box" style="width: 50%" />
</div>Here, width: 50% is specified directly on the image element. Despite the flex container appearing to have a definite size (considering both the document flow and the constraints imposed by the initial containing block through its ancestors) Chrome seems to disregard the percentage width when computing the flex-basis, resulting in the image falling back to its natural width of 200px. Firefox behaves differently (though the exact behavior is unclear), but in both browsers, the height is stretched as expected. Interestingly, even when setting the container’s width: 500px explicitly (instead of max-width), the outcome remains unchanged, suggesting that the container’s definite inline size state does not play a role in resolving the image’s percentage-based flex base size.
Chrome:
Firefox:
Adding height: 100% changes things again:
<!DOCTYPE html>
<div style="display: flex; max-width: 500px; font-family: Arial;">
<div>
Lorem ipsum...
</div>
<img src="box.jpg" alt="box" style="width: 50%; height: 100%;" />
</div>This time, neither browser stretches the image to match the full cross size of the flex line. The width behaves similarly to the previous example, but the height stretching now fails.
Chrome:
Firefox:
Compare with an equivalent Grid layout:
<!DOCTYPE html>
<div style="display: grid; grid-template-columns: minmax(0px,1fr) minmax(0px,1fr); max-width: 500px; font-family: Arial;">
<div>
Lorem ipsum...
</div>
<img src="box.jpg" alt="box" style="width: 100%; height: 100%;" />
</div> Here, both Chrome and Firefox respect width: 100% and height: 100%, and the image is sized correctly to fill its grid area.
Questions:
What parts of the CSS Flexbox specification could explain these discrepancies in sizing behavior, particularly regarding:
-
Why
width: 50%is ignored, even when the container appears to have a definite size? -
If the inline size of the container is not considered definite, could you clarify when the flex container's main size becomes definite in this scenario, and how percentage values like
width: 50%are handled in this context? -
Why does the image not stretch when
height:100%? -
Why Grid layout appears to handle these same percentage-based dimensions more predictably than Flexbox?
Activity
Loirooriol commentedon Mar 27, 2025
The flex item containing text is sized as
max-content, trying to fit all the text in a single line. But of course it's not possible for the single-line text plus the 50% wide image to fit in the container, so both items shrink.If you don't want the image to shrink, you can add
flex-shrink: 0.It's definite. Automatic size behaving as a definite
stretch, limited below 500px.align-self: stretchrequires the cross size property to compute toauto.That's an entirely different layout algorithm, so of course there are differences. Being more or less predictable is opinion-based.
gitspeaks commentedon Mar 27, 2025
Correct, but per CSS2 §10.5:
So
height: 100%on the image computes toautoif its containing block doesn’t have a definite height.This is also shown in Example 11 of CSS Sizing Level 4:
In the examples provided, the flex container (e.g containing block) has an indefinite height, so
height: 100%on the image is expected to compute toauto—but the item still doesn’t stretch.gitspeaks commentedon Mar 27, 2025
I agree. What confused me was 9.7(3), which says:
What exactly does that mean? Both items have by default have flex factor of 0 (flex-grow), yet they aren’t frozen.
Additionally, the algorithm distinguishes between two situations:
But step 3 gives three freezing conditions:
I understand why the last two conditions don’t apply —but what’s the purpose of the first one—“any item that has a flex factor of zero”?
And finally, even if everything is working as spec’d—why doesn’t Firefox reduce the image proportionally, stopping at its intrinsic width, like Chrome does? This feels like a basic behavior that layout engines ought to agree on.
Loirooriol commentedon Mar 27, 2025
No, it behaves as auto but doesn't compute to auto (on an element with children you could confirm this using inheritance). CSS2 used the same term for both behaviors, this terminology is now obsolete.
See #4525
You already quoted the spec that says you need to use the flex shrink factor here, which is not zero.
The difference is because of the automatic minimum size. I would need to check who is right, but probably Blink, since in Servo we have the same behavior and we tried to follow the spec closely.
gitspeaks commentedon Mar 27, 2025
I don't quite follow.
According to §3.2.1:
So "behave as auto" is a general term for two things:
a) when width/height computes to
autob) when it’s defined to behave as if
autowere specified — e.g. when a percentage height is used against an indefinite containerIf
height: 100%falls into case (b), then it's supposed to behave as ifheight: autowere specified.But here’s where I’m confused. Take this example:
The image has
height: auto, and yet it does stretch — even though no height is explicitly set on the flex container.So if
height: 100%is defined to behave as if auto were specified, andautoresults in stretching here, then shouldn’t100%also stretch?But from #4525 — and issue #4312 — it sounds like stretching should not occur in the
height: 100%case.So what does 'behave as auto' actually mean? The current definition suggests an equivalence that doesn't hold up in practice.
I understand that the flex line overflows the container’s main size, so the flex-shrink factor is used. What I don’t understand is the need for the condition 'Any item that has a flex factor of zero'.
An item can have a shrink factor >= 1 and a grow factor of 0, or vice versa. But why 'flex factor of 0' is relevant here?
In the context of 9.7(3), what actually matters is:
In the example, neither item satisfies the second condition, so we don’t freeze them — makes sense.
Why do we need the sentence “Any item that has a flex factor of zero”? Simply put, If we remove that line entirely, would the algorithm’s behavior actually change?
gitspeaks commentedon Mar 28, 2025
Anyway, once the flex line height is known, why doesn’t the image's height update to match it in a subsequent layout pass?