FlexboxLayout: honor flex-basis correctly - #12692
Merged
Merged
Conversation
flex-basis replaces the item's preferred size along the main axis, but flexbox_layout_info_main_axis() and flexbox_layout_unwrapped_main() summed preferred_bounded() and ignored it. A parent then sized the flexbox from the items' preferred sizes while taffy laid the items out at their basis, so the children overflowed their own layout. A growable item is the exception: it treats its basis as a floor to grow from rather than a cap, so it still needs room for its content, and summing the bases would collapse `flex-basis: 0` with `flex-grow: 1` (the CSS `flex: 1 1 0` idiom) to nothing. Taking the larger of the two is also what taffy does: its max-content flex fraction divides by the grow factor and then multiplies by it again, so the factor cancels out. The spec would scale every item by the line's largest fraction instead, but taffy, Chrome and Firefox all skip that step. The wrap heuristic measures items twice over, on purpose. The sqrt-area target uses the preferred contributions, since it estimates how much there is to place, but the line fitting uses the hypothetical sizes, because taffy breaks flex lines before any growing happens and the two must agree on where a line ends. The basis counts on both axes alike. That is what taffy does for a column; for a row it leaves the basis out of the max-content size instead, matching Webkit and Firefox, which is what lets the children overflow. That asymmetry comes from CSS sizing the inline axis shrink-to-fit and the block axis to max-content -- a writing-mode rule Slint has no equivalent of, so there is nothing here to tell a row and a column apart. The cross-axis info goes through taffy, which already honors the basis, so only the main-axis path (plus the sqrt-area wrap heuristics on both) needed the new helpers. Reporting min from the basis is still missing: an item with flex-shrink: 0 cannot shrink below it, but that needs the shrink factor in the min computation and is left for a follow-up.
Follow-up to the previous commit, which left this out: flexbox_layout_info_main_axis() took each item's own min, but an item with flex-shrink: 0 never goes below its hypothetical main size, so that is its real contribution. A parent could squeeze the flexbox below what its children need and they would overflow it. Note this is not limited to an explicit flex-basis: the hypothetical main size falls back to the preferred size, so flex-shrink: 0 alone is enough. flex_min_main() is never below constraint.min, so the reported minimum can only grow.
dfaure-kdab
force-pushed
the
wip/dfaure/flex-basis
branch
from
July 29, 2026 14:48
602801d to
1a31876
Compare
ogoffart
approved these changes
Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FlexboxLayout: account for flex-basis in the container's main-axis size
flex-basis replaces the item's preferred size along the main axis, but
flexbox_layout_info_main_axis() and flexbox_layout_unwrapped_main() summed
preferred_bounded() and ignored it. A parent then sized the flexbox from the
items' preferred sizes while taffy laid the items out at their basis, so the
children overflowed their own layout.
A growable item is the exception: it treats its basis as a floor to grow from
rather than a cap, so it still needs room for its content, and summing the
bases would collapse
flex-basis: 0withflex-grow: 1(the CSSflex: 1 1 0idiom) to nothing. Taking the larger of the two is also what taffy does: its
max-content flex fraction divides by the grow factor and then multiplies by it
again, so the factor cancels out. The spec would scale every item by the line's
largest fraction instead, but taffy, Chrome and Firefox all skip that step.
The wrap heuristic measures items twice over, on purpose. The sqrt-area target
uses the preferred contributions, since it estimates how much there is to
place, but the line fitting uses the hypothetical sizes, because taffy breaks
flex lines before any growing happens and the two must agree on where a line
ends.
The basis counts on both axes alike. That is what taffy does for a column; for
a row it leaves the basis out of the max-content size instead, matching Webkit
and Firefox, which is what lets the children overflow. That asymmetry comes
from CSS sizing the inline axis shrink-to-fit and the block axis to max-content
-- a writing-mode rule Slint has no equivalent of, so there is nothing here to
tell a row and a column apart.
The cross-axis info goes through taffy, which already honors the basis, so
only the main-axis path (plus the sqrt-area wrap heuristics on both) needed
the new helpers.
Reporting min from the basis is still missing: an item with flex-shrink: 0
cannot shrink below it, but that needs the shrink factor in the min
computation and is left for a follow-up.
Before/after screenshot
FlexboxLayout: a non-shrinkable item raises the container's minimum
Follow-up to the previous commit, which left this out: flexbox_layout_info_main_axis()
took each item's own min, but an item with flex-shrink: 0 never goes below its
hypothetical main size, so that is its real contribution. A parent could squeeze
the flexbox below what its children need and they would overflow it.
Note this is not limited to an explicit flex-basis: the hypothetical main size
falls back to the preferred size, so flex-shrink: 0 alone is enough.
flex_min_main() is never below constraint.min, so the reported minimum can only
grow.