Fix display:contents transparency in box-tree construction#453
Open
UMCEKO wants to merge 3 commits into
Open
Conversation
This was referenced Jun 13, 2026
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Three related fixes, covered by packages/blitz-html/tests/display_contents.rs: 1. The inline-vs-block classification in collect_layout_children treated a display:contents child as opaque (only setting has_contents), so a container whose in-flow children were all contents wrappers classified as all_inline and became an inline root, embedding hoisted BLOCK children as zero-width inline boxes. Classification now recurses into contents children (work-stack), since they are transparent for box generation. 2. The DisplayInside::Contents arm hoisted each child's LAYOUT CHILDREN (via collect_layout_children) instead of the children themselves, skipping a generation: leaf children contributed nothing and disappeared from the layout tree. It now pushes the children directly, recursing only through nested contents nodes (comments and whitespace filtered like the other collection paths). 3. The whitespace-only anonymous-block cleanup removed the anon block with layout_children.pop(), assuming it was the most recent entry. Hoisted contents children can land after it, so pop() dropped a real child and left the removed anon block's stale id in the list (slab 'invalid key' panic in resolve_layout_children). Remove by identity instead.
…casts no classification vote Two refinements to contents transparency in collect_layout_children: 1. The all_out_of_flow early-return pushed the container's DIRECT children, so a display:contents node holding the out-of-flow elements was itself pushed as a layout box and the abspos children were laid out against it (content-sized, e.g. 0x5000) instead of stretching to the real containing block. Extracted push_hoisted_children_and_pseudos (also reused by the DisplayInside::Contents arm, which gains ::before/::after support) and used it there. 2. The classification scan cleared all_out_of_flow for any contents child. Transparency means the contents node casts no vote — its children (already visited via the work-stack) decide. A container whose only box-generating descendants are out-of-flow now correctly takes the all_out_of_flow path instead of becoming an inline root. Repro shape (kopuz route shell): scroller > [comment, contents > abspos inset:0 page] — the page sized to its content (no scroll capacity, page 50k px tall) instead of the scroller's padding box. WPT css-grid+css-flexbox: no changes (1154 passes before and after).
057ff20 to
818a19f
Compare
Contributor
Author
|
Rebased the mac ci fix |
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.
Stacked on #452 (contains its commit; will rebase once it lands).
display: contentsis transparent for box generation, but three places incollect_layout_childrentreated the contents element as opaque. Together they made a common Dioxus/Tailwind structure (aclass="contents"shell between a scroll container and absolutely-positioned pages) lay out as zero-size or content-size boxes. Each fix is covered by a test inpackages/blitz-html/tests/display_contents.rs:Classification didn't recurse into contents children. A container whose in-flow children were all contents wrappers classified as
all_inline(the existingTODO: make "all_inline" detection work in the presence of display:contents) and became an inline root, embedding hoisted block children as zero-width inline boxes. The scan now recurses through contents children; the contents node itself casts no vote — including not clearingall_out_of_flow, so a container whose only box-generating descendants are out-of-flow takes the out-of-flow path instead of becoming an inline root.The
DisplayInside::Contentsarm hoisted the wrong generation. It calledcollect_layout_childrenon each child, which pushes the child's layout children — so leaf children contributed nothing and vanished from the layout tree. Extractedpush_hoisted_children_and_pseudos, which pushes the children themselves and recurses only through nested contents nodes; the arm also gains::before/::aftersupport. The same helper now serves theall_out_of_flowearly-return, which previously pushed the container's direct children — a contents node holding the out-of-flow elements was itself pushed as a layout box, and anabsolute inset:0child then sized against it instead of the real containing block (content-sized: a real-app page measured 1745x50517 inside a 1004x1251 scroller, leaving nothing scrollable).Whitespace-only anonymous-block cleanup corrupted the child list. It removed the anon block with
layout_children.pop(), assuming it was the most recent entry. Hoisted contents children can land after it, sopop()dropped a real child and left the removed anon block's stale id in the list — a slabinvalid keypanic inresolve_layout_children. Removal is now by identity.WPT
css/css-grid+css/css-flexbox: 1154 tests pass before and after.