Hoist out-of-flow (absolute/fixed) boxes to their containing block - #1141
Closed
nicoburns wants to merge 5 commits into
Closed
Hoist out-of-flow (absolute/fixed) boxes to their containing block#1141nicoburns wants to merge 5 commits into
nicoburns wants to merge 5 commits into
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This was referenced Aug 22, 2026
staging-devin-ai-integration
Bot
force-pushed
the
devin/1787345886-position-static-fixed
branch
from
August 23, 2026 19:04
72ffc8f to
70c0e19
Compare
staging-devin-ai-integration
Bot
force-pushed
the
devin/1787348650-oof-hoisting
branch
from
August 23, 2026 19:04
2d03982 to
6e7ed2b
Compare
staging-devin-ai-integration
Bot
force-pushed
the
devin/1787345886-position-static-fixed
branch
from
August 24, 2026 19:14
70c0e19 to
b841a66
Compare
staging-devin-ai-integration
Bot
force-pushed
the
devin/1787348650-oof-hoisting
branch
2 times, most recently
from
August 25, 2026 16:26
42da269 to
9e237c0
Compare
staging-devin-ai-integration
Bot
force-pushed
the
devin/1787345886-position-static-fixed
branch
from
August 25, 2026 16:26
b841a66 to
ee5f7bd
Compare
staging-devin-ai-integration
Bot
force-pushed
the
devin/1787345886-position-static-fixed
branch
from
August 25, 2026 17:09
ee5f7bd to
6caef10
Compare
staging-devin-ai-integration
Bot
force-pushed
the
devin/1787348650-oof-hoisting
branch
from
August 25, 2026 17:09
9e237c0 to
683ef33
Compare
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.
Objective
Implement browser-correct out-of-flow hoisting:
position: absolute/fixedboxes are now laid out by their containing block (nearest positioned ancestor forabsolute, the root forfixed) rather than always by their DOM parent, withLayout.locationrelative to that containing block. Stacked on #1140 (Position::Static/Fixed).Architecture follows Blink's model (candidate bubbling + per-fragment persistence), as discussed in the design conversation.
Context
Candidate bubbling (Blink's
oof_positioned_candidates/oof_positioned_descendants)OofCandidate { node, order, position, static_position: Point<StaticPosition> }whereStaticPosition { anchor, edge, fallback_anchor, fallback_edge, safe_extent }records the box's static position (including flex/grid alignment edges and safe-alignment fallback), computed in-algorithm by the DOM parent.LayoutOutput.oof_candidates: OofCandidates— lazyOption<Box<Vec<_>>>storage so the no-OOF case allocates nothing; lists are moved (take/append), not copied.perform_oof_layout(newsrc/compute/oof.rs, refactored from the old per-algorithm absolute-layout code), claims candidates the current node is the containing block for, lays them out against its padding box, re-sweeps candidates surfaced by OOF children (fixed inside absolute), and passes unclaimed candidates up through its ownLayoutOutput.compute_root_layoutruns the final pass: the root is the initial containing block forfixedand forabsolutewith no positioned ancestor.LayoutOutputis nowCloneinstead ofCopy), so a cache hit at an intermediate node re-propagates hoisted descendants without descending into the skipped subtree — this is what keeps incremental layout working.Containing-block-relative locations + rounding
Layout.locationis relative to its containing block's border box; scrollable overflow contributions likewise move to the containing block.LayoutPartialTree::set_hoisted_children/add_hoisted_children;round_layoutskips hoisted boxes when walking DOM children and instead recurses into them via newRoundTree::is_hoisted/hoisted_child_count/get_hoisted_child_id, so rounding accumulates offsets through the containing block (which the location is relative to) and each node is visited exactly once.Test fixtures
The gentest fixture diff is large but mechanical: the test base stylesheet sets
position: relativeon all divs (matching taffy's old default), but the generator captured only the inlinepositionstyle — so withstaticas the new default, generated tests silently disagreed with what Chrome actually laid out. The generator now records the computed position (and measures OOF boxes against their containing block), making every fixture'sposition: relativeexplicit. New hand-written tests intests/hand_written/oof_hoisting.rscover hoisting past static parents, containing-block-relative static positions per layout mode, fixed-to-root (including fixed inside absolute re-sweep), cache-hit re-propagation and invalidation, and rounding via the containing block.Feedback wanted
DetailedGridInfo::resolve_absolute_grid_area(needed for non-direct descendants whose CB is a grid) is planned as a follow-up PR.Position::Fixedcurrently only treats the root as its containing block; style-created fixed containing blocks (transforms etc.) are left to embedders (Blitz) via the trait layer.Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/65c5463061c8403bade7888271d5eeb4
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/65c5463061c8403bade7888271d5eeb4?variant=devin-insiders
Requested by: @nicoburns