LibWeb: Don't use BFC auto height for non-BFC abspos elements

While CSS 2.2 does tell us to use the "auto height for BFC roots"
calculation when resolving auto heights for abspos elements, that
doesn't make sense for other formatting context roots, e.g flex.

In lieu of implementing the entire new absolute positioning model from
CSS-POSITION-3, this patch borrows one small nugget from it: using
fit-content height as the auto height for non-BFC-root abspos elements.
This commit is contained in:
Andreas Kling 2023-06-20 13:20:08 +02:00
parent 38a6b7ad3d
commit c808f6c637
Notes: sideshowbarker 2024-07-17 03:30:41 +09:00
4 changed files with 58 additions and 15 deletions

View file

@ -0,0 +1,8 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (1,1) content-size 798x0 [BFC] children: not-inline
Box <body> at (9,9) content-size 512.859375x19.46875 positioned flex-container(column) [FFC] children: not-inline
BlockContainer <div> at (10,10) content-size 510.859375x17.46875 flex-item [BFC] children: inline
line 0 width: 510.859375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 60, rect: [10,10 510.859375x17.46875]
"Diese Website nutzt Cookies und vergleichbare Funktionen zur"
TextNode <#text>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html><style>
* {
border: 1px solid black;
}
html {
background: white;
}
body {
display: flex;
flex-flow: column nowrap;
position: absolute;
top: 0px;
left: 0px;
background: pink;
}
div {
min-height: 0px;
background: orange;
}
</style><body><div>Diese Website nutzt Cookies und vergleichbare Funktionen zur

View file

@ -305,6 +305,22 @@ CSSPixelSize FormattingContext::solve_replaced_size_constraint(CSSPixels input_w
return { w, h };
}
Optional<CSSPixels> FormattingContext::compute_auto_height_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout) const
{
// NOTE: CSS 2.2 tells us to use the "auto height for block formatting context roots" here.
// That's fine as long as the box is a BFC root.
if (creates_block_formatting_context(box)) {
if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
return {};
return compute_auto_height_for_block_formatting_context_root(box);
}
// NOTE: For anything else, we use the fit-content height.
// This should eventually be replaced by the new absolute positioning model:
// https://www.w3.org/TR/css-position-3/#abspos-layout
return calculate_fit_content_height(box, available_space);
}
// https://www.w3.org/TR/CSS22/visudet.html#root-height
CSSPixels FormattingContext::compute_auto_height_for_block_formatting_context_root(Box const& root) const
{
@ -798,10 +814,6 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
// If all three of top, height, and bottom are auto:
if (top.is_auto() && height.is_auto() && bottom.is_auto()) {
// (If we haven't done inside layout yet, we can't compute the auto height.)
if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
return;
// First set any auto values for margin-top and margin-bottom to 0,
if (margin_top.is_auto())
margin_top = CSS::Length::make_px(0);
@ -813,7 +825,10 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
top = CSS::Length::make_px(static_position.y());
// and finally apply rule number three below.
height = CSS::Size::make_px(compute_auto_height_for_block_formatting_context_root(box));
auto maybe_height = compute_auto_height_for_absolutely_positioned_element(box, available_space, before_or_after_inside_layout);
if (!maybe_height.has_value())
return;
height = CSS::Size::make_px(maybe_height.value());
solve_for_bottom();
}
@ -853,12 +868,11 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
// 1. If top and height are auto and bottom is not auto,
if (top.is_auto() && height.is_auto() && !bottom.is_auto()) {
// (If we haven't done inside layout yet, we can't compute the auto height.)
if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
return;
// then the height is based on the Auto heights for block formatting context roots,
height = CSS::Size::make_px(compute_auto_height_for_block_formatting_context_root(box));
auto maybe_height = compute_auto_height_for_absolutely_positioned_element(box, available_space, before_or_after_inside_layout);
if (!maybe_height.has_value())
return;
height = CSS::Size::make_px(maybe_height.value());
// and solve for top.
solve_for_top();
@ -875,12 +889,11 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
// 3. If height and bottom are auto and top is not auto,
else if (height.is_auto() && bottom.is_auto() && !top.is_auto()) {
// (If we haven't done inside layout yet, we can't compute the auto height.)
if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
return;
// then the height is based on the Auto heights for block formatting context roots,
height = CSS::Size::make_px(compute_auto_height_for_block_formatting_context_root(box));
auto maybe_height = compute_auto_height_for_absolutely_positioned_element(box, available_space, before_or_after_inside_layout);
if (!maybe_height.has_value())
return;
height = CSS::Size::make_px(maybe_height.value());
// and solve for bottom.
solve_for_bottom();

View file

@ -146,6 +146,8 @@ protected:
void compute_height_for_absolutely_positioned_non_replaced_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout);
void compute_height_for_absolutely_positioned_replaced_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout);
[[nodiscard]] Optional<CSSPixels> compute_auto_height_for_absolutely_positioned_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout) const;
Type m_type {};
FormattingContext* m_parent { nullptr };