render: z-index paint layers and clear ending float zones

Paint order was pure tree order, so a dropdown/overlay declared before a
later sibling lost to it and a z:-1 decorative backdrop covered its own
content. A positioned element with a non-zero z-index now lifts its
whole subtree into a separate paint layer: negative layers under the
normal flow, positive above it, each sorted ascending with tree order
preserved within equal z. Nested z roots paint inside their ancestor
root's subtree in tree order, the pragmatic core of CSS stacking
contexts.

clear (left/right/both, previously unparsed) now ends the float zone,
so a clearfix element drops below the float at full width instead of
joining the flow column beside it.

Repro-verified: an earlier z:10 overlay paints over a later sibling, a
later z:-1 backdrop paints under earlier content, and the clear repro
matches Chromium within 3px on every measure. Spot set unchanged or
slightly improved; obstacle course 33/33.
This commit is contained in:
SGavrl committed 2026-07-16 13:10:28 +00:00
1 parent 953292563d
commit 22f33e4dec
4 files changed
+93 -2

No files matched your search

+16 -1
View File
@@ -2250,9 +2250,24 @@ fn build_children_with_float_zone(
// approximate bound beats an unbounded one.
let float_height_budget = estimate_float_height(tree, dom_children[float_idx], styles);
const ASSUMED_FLOW_WIDTH: f32 = 500.0;
// `clear` on a sibling ends the zone: the cleared element moves below the
// float (the clearfix idiom), so it must not join the flow column beside it.
let clears_this_float = |cid: NodeId| {
let Some(c) = styles.get(&cid).and_then(|s| s.clear) else { return false };
match (float_side, c) {
(_, crate::Clear::Both) => true,
(Some(crate::Float::Left), crate::Clear::Left) => true,
(Some(crate::Float::Right), crate::Clear::Right) => true,
_ => false,
}
};
let mut zone_end = float_idx + 1;
let mut flow_height_estimate = 0.0f32;
while zone_end < dom_children.len() && !is_heading(dom_children[zone_end]) && !is_float(dom_children[zone_end]) {
while zone_end < dom_children.len()
&& !is_heading(dom_children[zone_end])
&& !is_float(dom_children[zone_end])
&& !clears_this_float(dom_children[zone_end])
{
flow_height_estimate += estimate_text_height(tree, dom_children[zone_end], styles, ASSUMED_FLOW_WIDTH);
zone_end += 1;
if flow_height_estimate >= float_height_budget {