Skip to content

Block/Flexbox/Grid: floor content width and child stretch/available sizes at zero - #1178

Merged
nicoburns merged 2 commits into
mainfrom
devin/1788440338-block-clamp-negative-widths
Sep 3, 2026
Merged

Block/Flexbox/Grid: floor content width and child stretch/available sizes at zero#1178
nicoburns merged 2 commits into
mainfrom
devin/1788440338-block-clamp-negative-widths

Conversation

@nicoburns

@nicoburns nicoburns commented Sep 3, 2026

Copy link
Copy Markdown
Member

Objective

Stacked on #1177. Several places computed "container (or grid area / flex line) size minus insets/margins" and passed the result on unfloored, so when padding/border or a child's margins exceed the container, children received negative known_dimensions / available_space / percentage bases — and in the flexbox case a negative used size.

Block (perform_final_layout_on_in_flow_children):

let container_inner_width = container_outer_width - resolved_content_box_inset.horizontal_axis_sum();
let stretch_width  = container_inner_width - item_non_auto_x_margin_sum;   // -> known_dimensions.width & available_space.width
let available_width = container_inner_width - item_non_auto_x_margin_sum;  // floats

All floored at zero (.max(0.0)), including the float-avoiding slot.stretch_width.max(min_auto_width) case.

Flexbox: the container's inner available space (determine_available_space), the cross-axis stretch size handed to items as a known dimension (determine_flex_base_size, the intrinsic-main-size pass), main_stretch_size, cross_stretch_size, and the final stretched cross size in determine_used_cross_size (line_cross_size - margins) are floored at zero. The last one is user-visible: a stretched item in a column container whose horizontal margins exceed the container width ended up with width = -20 in the final layout (Chrome: 0).

Grid: grid_area_size - margins in GridItem::available_space/keyword sizing and in align_and_position_item floored at zero (only measure-function inputs were affected; final item sizes were already floored).

This matches Blink, which never hands a child a negative constraint: CalculateChildAvailableSizeShrinkLogicalSize(..).ClampNegativeToZero(), stretch resolves to max(border+padding, available − margins), fit-content to (available − margins).ClampNegativeToZero(), and ResolveInlineLength DCHECK_GE(available_size, 0).

Tests:

  • Chrome-generated gentest fixtures block_margin_x_exceeds_container_width, block_padding_exceeds_container_width, flex_column_stretch_margin_x_exceeds_container_width (children width="0" at the margin/padding edge; all fail on main, pass here).
  • tests/hand_written/negative_available_space.rs: block / flex-column / grid containers with a margin-overflowing leaf; asserts the leaf's measure function never sees a negative known dimension or definite available space and that the leaf is 0 wide (all three fail on main).
  • All 6081 existing fixtures unchanged.

Context

Follow-up from the investigation in #1177 (negative inline widths were observed inside the discarded min-content pass that #1177 removes, but the arithmetic is wrong regardless). Downstream, DioxusLabs/blitz#835 additionally clamps Blitz's own margin/inset subtraction in inline layout; that covers a different subtraction (Blitz's, after known_dimensions/node_size override the available space) so both are kept.

I could not construct a grid fixture where Chrome and Taffy disagree on final layout (grid already floors item sizes; a %/1fr/wrapping grandchild under a 0-wide item resolves the same from −20 and 0), so the grid change is covered by the hand-written measure-input test only.

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/3a0b8cc210c041d8955c841fb2a76a8e
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/3a0b8cc210c041d8955c841fb2a76a8e?variant=devin-insiders
Requested by: @nicoburns

@staging-devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@staging-devin-ai-integration staging-devin-ai-integration Bot changed the title Block: floor container content width and child stretch/available width at zero Block/Flexbox/Grid: floor content width and child stretch/available sizes at zero Sep 3, 2026
Base automatically changed from devin/1788439473-grid-skip-unaffected-contributions to main September 3, 2026 14:22
…h at zero

A block container whose padding/border exceeds its width, or a child whose
horizontal margins exceed the container's content width, previously produced
negative content/stretch widths that were passed down as known dimensions and
available space (and to measure functions). Browsers floor these at zero.
…n margins exceed the container

Stretched flex items whose cross-axis margins exceeded the line were given a
negative used cross size, and flex/grid items were measured with negative
known dimensions / available space. Blink clamps every child constraint at
zero (CalculateChildAvailableSize, stretch = max(border+padding, available -
margins)); do the same here.

Adds a Chrome-generated flex fixture (items end up 0 wide, matching Chrome)
and a hand-written test asserting that block/flex/grid leaves never receive
negative layout inputs.
@nicoburns
nicoburns force-pushed the devin/1788440338-block-clamp-negative-widths branch from 51bcfcd to 50d5d2d Compare September 3, 2026 14:22
@nicoburns
nicoburns enabled auto-merge (squash) September 3, 2026 14:22
@nicoburns
nicoburns merged commit 1b918ba into main Sep 3, 2026
28 checks passed
@nicoburns
nicoburns deleted the devin/1788440338-block-clamp-negative-widths branch September 3, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant