Skip to content

Fix nested flex/grid baseline selection, synthesized baselines, and grid-order baseline selection - #1113

Open
nicoburns wants to merge 5 commits into
devin/1786752736-last-baseline-alignmentfrom
devin/1786908783-baseline-fixes
Open

Fix nested flex/grid baseline selection, synthesized baselines, and grid-order baseline selection#1113
nicoburns wants to merge 5 commits into
devin/1786752736-last-baseline-alignmentfrom
devin/1786908783-baseline-fixes

Conversation

@nicoburns

@nicoburns nicoburns commented Aug 16, 2026

Copy link
Copy Markdown
Member

Objective

Fix two groups of baseline-alignment bugs (stacked on #1111) that cause WPT failures in Blitz's css-flexbox/alignment and css-grid/alignment suites (horizontal-tb).

Changes

1. Flex container baseline export: consider items in either baseline group (src/compute/flexbox.rs)

When a multi-line flex container exports its first/last baseline, the item used was previously only searched among items participating in the same-kind baseline group. Chrome (and css-align) consider items participating in any baseline alignment:

first baseline item = first item in cross-start-most line participating in first-baseline alignment
                      else first item participating in last-baseline alignment
                      else the line's first item
last baseline item  = symmetric, from the cross-end-most line, falling back to the line's last item

Addresses: flex-align-baseline-flex-001/003, grid-align-baseline-flex-001/003, flex-align-baseline-grid-001, grid-align-baseline-grid-001.

2. Grid container baseline export (src/compute/grid/mod.rs)

  • The item that generates the container's baseline is now selected in grid-modified document order (first by row, then by logical column — negated for RTL since taffy's column indexes are visually reversed — with document-order ties preserved). Previously only the row was considered, so an earlier-in-document item in a later column won incorrectly. This is done with linear scans (min/max + min_by_key, whose first-of-equal semantics preserve document-order ties) — no sorting.
  • item.baseline is now stored from the item's final layout output (like last_baseline already was), so a nested grid/flex item's natural baseline propagates even when it isn't part of a multi-item baseline group. Synthesis from the border box (unwrap_or(height)) still applies when the item has no natural baseline. This fixes baseline propagation through two levels of nested grids, including inner borders/padding.

Addresses: grid-align-baseline.html, grid-align-baseline-004/005, grid-baseline-004, grid-baseline-align-001, grid-self-alignment-baseline-with-grid-001..004, grid-self-baseline-horiz-001.

3. Grid baseline shims resolved after column sizing (src/compute/grid/track_sizing.rs)

resolve_item_baselines previously ran during the inline track-sizing pass, measuring items with the container's inner width as the containing block — so items with width: 100% or aspect-ratio in percentage tracks measured wildly wrong baselines. Shims only affect the block axis, so baseline resolution now runs at the start of the block pass, once columns are sized, and measures each item against its grid-area width:

let grid_area_width = item.track_range_excluding_lines(Inline).map(|i| columns[i].base_size).sum();
let known_dimensions = item.known_dimensions(tree, grid_area_size); // applies stretch + % resolution

Addresses: grid-self-baseline-008 (canvases with aspect-ratio + width:100% in 25% tracks), grid-baseline-004.

4. Row-spanning grid items: last-baseline participation uses the end-most row (src/compute/grid/track_sizing.rs, src/compute/grid/mod.rs)

Per css-align baseline-sharing-group rules, an item spanning multiple rows participates in first-baseline alignment in its start-most row but in last-baseline alignment in its end-most row. Previously both groups were keyed on row start, so:

  • resolve_item_baselines now resolves the two groups in separate passes: first-baseline items grouped by row-start line (as before), last-baseline items grouped by row-end line, so a row-spanning item shims/aligns against the items it shares its end row with. Each pass returns early (before any sorting) unless at least two items participate in that kind of baseline alignment, and the whole function is still gated on the container having baseline-aligned items at all.
  • The grid container's exported last baseline is now generated from items whose grid area ends in the last row (row_indexes.end == max end) rather than items that start in the row-start-sorted last row.

Addresses: grid-self-alignment-baseline-with-grid-003/004 (verified passing in Blitz's WPT runner with last-baseline plumbing enabled, with no regressions across the css-flexbox/alignment and css-grid/alignment suites; grid-align-baseline-004 also went 1/2 → 2/2).

Performance notes

The per-layout container-baseline export path does no sorting (linear scans only). Sorting only happens in resolve_item_baselines, which is skipped entirely unless the container has baseline-aligned items, and each group pass is skipped unless ≥2 items participate in that group.

Tests

27 new gentest fixtures (Chrome-for-Testing as oracle), all passing, covering: nested wrap/wrap-reverse flex baselines (first/last/mixed baseline groups), nested & double-nested grid baselines with borders/padding, row-spanning nested grids and row-spanning inner items (first + last baseline), synthesized baselines for empty items (with margins), empty-grid containers, grid-order/column-order baseline selection (LTR + RTL), and aspect-ratio items in percentage tracks.

One hand-written expectation (grid_baselines in tests/hand_written/last_baseline.rs) encoded the old behavior (synthesizing from the border box even when the item has a natural measure-function baseline) and was updated to expect the item's natural baseline.

cargo test --workspace, cargo fmt, and cargo clippy --workspace are all clean.

Context

Stacked on #1111 (devin/1786752736-last-baseline-alignment). WPT sources under css/css-flexbox/alignment and css/css-grid/alignment were used as ground truth.

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/d7a77a76f9114c3295372c0cc74899a9
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

Items spanning multiple rows participate in the baseline-sharing group
of their end-most row for last-baseline alignment (and their start-most
row for first-baseline alignment). Group items by row end when resolving
last-baseline shims, and select the grid container's exported last
baseline from items ending in the last row rather than starting in it.
Select the container's first/last baseline item with linear scans
(min/max + min_by_key in grid order) instead of sorting the items, and
skip the per-group sort in resolve_item_baselines when fewer than two
items participate in that baseline alignment group.
@staging-devin-ai-integration
staging-devin-ai-integration Bot force-pushed the devin/1786908783-baseline-fixes branch from 093b58c to bb30dbf Compare August 19, 2026 11:49
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