Skip to content

[css-flexbox-1] Inconsistent sizing of replaced elements in flex containers #12012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gitspeaks opened this issue Mar 27, 2025 · 6 comments
Closed
Labels
Closed as Question Answered Used when the issue is more of a question than a problem, and it's been answered. css-flexbox-1 Current Work

Comments

@gitspeaks
Copy link

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.

Image


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:

Image

Firefox:

Image


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:

Image

Firefox:

Image


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.

Image


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?

@Loirooriol
Copy link
Contributor

Why width: 50% is ignored, even when the container appears to have a definite size?

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.

If the inline size of the container is not considered definite

It's definite. Automatic size behaving as a definite stretch, limited below 500px.

Why does the image not stretch when height:100%?

align-self: stretch requires the cross size property to compute to auto.

Why Grid layout appears to handle these same percentage-based dimensions more predictably than Flexbox?

That's an entirely different layout algorithm, so of course there are differences. Being more or less predictable is opinion-based.

@Loirooriol Loirooriol added css-flexbox-1 Current Work Closed as Question Answered Used when the issue is more of a question than a problem, and it's been answered. labels Mar 27, 2025
@gitspeaks
Copy link
Author

Why does the image not stretch when height:100%?

align-self: stretch requires the cross size property to compute to auto.

Correct, but per CSS2 §10.5:

Specifies a percentage height. The percentage is calculated with respect to the height of the generated box’s containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to auto.

So height: 100% on the image computes to auto if its containing block doesn’t have a definite height.

This is also shown in Example 11 of CSS Sizing Level 4:

In this example, the container’s height is indefinite, which causes a percentage height on the child to behave as auto, so height: stretch behaves as auto as well.

.parent { height: auto; margin: 0; }
.child  { height: stretch; margin: 10px; }

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 to auto—but the item still doesn’t stretch.

@gitspeaks
Copy link
Author

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.

I agree. What confused me was 9.7(3), which says:

“Any item that has a flex factor of zero”

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:

If the sum is less than the flex container’s inner main size, use the flex grow factor for the rest of this algorithm; otherwise, use the flex shrink factor.

But step 3 gives three freezing conditions:

  • Any item that has a flex factor of zero
  • If using the flex grow factor: any item with a flex base size greater than its hypothetical main size
  • If using the flex shrink factor: any item with a flex base size smaller than its hypothetical main size

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
Copy link
Contributor

So height: 100% on the image computes to auto

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

Both items have by default have flex factor of 0 (flex-grow)

You already quoted the spec that says you need to use the flex shrink factor here, which is not zero.

why doesn’t Firefox reduce the image proportionally, stopping at its intrinsic width, like Chrome does?

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
Copy link
Author

So height: 100% on the image computes to auto

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.

I don't quite follow.

According to §3.2.1:

To have a common term for both when width/height computes to auto and when it is defined to behave as if auto were specified (as in the case of block percentage heights resolving against an indefinite size, see CSS2§10.5), the property is said to behave as auto in both of these cases.

So "behave as auto" is a general term for two things:

a) when width/height computes to auto
b) when it’s defined to behave as if auto were specified — e.g. when a percentage height is used against an indefinite container

If height: 100% falls into case (b), then it's supposed to behave as if height: auto were specified.

But here’s where I’m confused. Take this example:

<div style="display: flex; max-width: 500px; font-family: Arial;">
  <div>
    Lorem ipsum dolor sit amet...
  </div>
  <img src="box.jpg" alt="box" style="width: 50%; height: auto;" />
</div>

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, and auto results in stretching here, then shouldn’t 100% 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.


Both items have by default have flex factor of 0 (flex-grow)

You already quoted the spec that says you need to use the flex shrink factor here, which is not zero.

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:

  • If using the grow factor: any item whose flex base size is greater than its hypothetical main size
  • If using the shrink factor: any item whose flex base size is smaller than its hypothetical main size

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
Copy link
Author

Anyway, once the flex line height is known, why doesn’t the image's height update to match it in a subsequent layout pass?

<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. Labore, optio? Recusandae nesciunt voluptatem reiciendis deserunt voluptates quod nostrum aperiam ad eius similique explicabo quasi placeat aliquam cumque laboriosam qui animi hic voluptatum, iusto nemo molestiae possimus deleniti dolorum! Quae laboriosam ratione deleniti corporis facere temporibus adipisci, illo doloribus? Maxime sed dicta soluta animi nesciunt saepe eum. Excepturi nam enim numquam ipsam placeat praesentium, optio eligendi natus odit quo sunt nobis quisquam tempora molestias explicabo eveniet est nulla magnam maxime! Optio, maiores temporibus.
  </div>
  <img src="box.jpg" alt="box" style="width: 50%; height: 100%; font-family: Arial; " />
</div>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed as Question Answered Used when the issue is more of a question than a problem, and it's been answered. css-flexbox-1 Current Work
Projects
None yet
Development

No branches or pull requests

2 participants