Skip to content

Inline roots: apply aspect-ratio to known dimensions at final layout#464

Draft
UMCEKO wants to merge 5 commits into
DioxusLabs:mainfrom
UMCEKO:pr/inline-aspect-ratio
Draft

Inline roots: apply aspect-ratio to known dimensions at final layout#464
UMCEKO wants to merge 5 commits into
DioxusLabs:mainfrom
UMCEKO:pr/inline-aspect-ratio

Conversation

@UMCEKO

@UMCEKO UMCEKO commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Stacked on #453 (contains its commits). The included layout tests additionally require DioxusLabs/taffy#965 (block aspect-ratio definite height) to pass — draft until both land.

An inline root with aspect-ratio and a stretched (known) width never derived its height from the ratio, so e.g. an aspect-square cover containing only inline content sized itself from that content instead. Paired with taffy#965 (the block-layout half of the same gap) and gated to RunMode::PerformLayout for the same reason: measure-pass widths are tentative and must not transfer through the ratio.

Layout tests in packages/blitz-html/tests/image_layout.rs cover the <img> sizing shapes: explicit, percentage, and aspect-ratio-derived container heights, the flex-shelf card shape, and a full-fidelity Tailwind card (where preflight's img { display: block } routes through taffy block layout rather than this inline path — both halves are needed).

UMCEKO added 4 commits June 16, 2026 02:16
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).
An inline root with aspect-ratio and a stretched (known) width never
derived its height from the ratio, so e.g. a Tailwind aspect-square
cover containing only an <img> sized itself from the image's intrinsic
aspect instead: a 16:9 thumbnail in a square card laid out 16:9 and the
percentage-height image letterboxed instead of cover-cropping.

Paired with the taffy block fix (aspect-derived definite height) and
gated to PerformLayout for the same reason: measure-pass widths are
tentative and must not transfer through the ratio.

Layout tests in packages/blitz-html/tests/image_layout.rs (injected
raster image data; explicit / percentage / aspect-ratio-derived parent
heights, and the flex-shelf card shape).
@UMCEKO UMCEKO force-pushed the pr/inline-aspect-ratio branch from b8be46c to 51a8052 Compare June 15, 2026 23:17
Match taffy #965 (now merged): drop the `RunMode::PerformLayout` gate and
apply `aspect-ratio` to `known_dimensions` directly. The transfer self-gates
because blitz's block parent is taffy, which fills `known_dimensions` only as
a real constraint and leaves it `None` while probing intrinsic sizes — so
measure passes stay content-based without a run-mode special case. Only a
newly-derived axis is adopted (an incoming known size is left as the parent
resolved it), mirroring the taffy implementation.
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