diff --git a/Base/res/html/tests/abspos-flexbox-with-auto-height.html b/Base/res/html/tests/abspos-flexbox-with-auto-height.html new file mode 100644 index 0000000000..0eb5ce9ce3 --- /dev/null +++ b/Base/res/html/tests/abspos-flexbox-with-auto-height.html @@ -0,0 +1,12 @@ + diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index 61b8a0fcf0..b735980240 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -386,12 +386,12 @@ void FormattingContext::compute_width_for_absolutely_positioned_element(Box cons compute_width_for_absolutely_positioned_non_replaced_element(box, available_space); } -void FormattingContext::compute_height_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space) +void FormattingContext::compute_height_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout) { if (is(box)) - compute_height_for_absolutely_positioned_replaced_element(static_cast(box), available_space); + compute_height_for_absolutely_positioned_replaced_element(static_cast(box), available_space, before_or_after_inside_layout); else - compute_height_for_absolutely_positioned_non_replaced_element(box, available_space); + compute_height_for_absolutely_positioned_non_replaced_element(box, available_space, before_or_after_inside_layout); } CSSPixels FormattingContext::compute_width_for_replaced_element(LayoutState const& state, ReplacedBox const& box, AvailableSpace const& available_space) @@ -636,13 +636,17 @@ void FormattingContext::compute_width_for_absolutely_positioned_replaced_element } // https://drafts.csswg.org/css-position-3/#abs-non-replaced-height -void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_element(Box const& box, AvailableSpace const& available_space) +void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout) { // 5.3. The Height Of Absolutely Positioned, Non-Replaced Elements // For absolutely positioned elements, the used values of the vertical dimensions must satisfy this constraint: // top + margin-top + border-top-width + padding-top + height + padding-bottom + border-bottom-width + margin-bottom + bottom = height of containing block + // NOTE: This function is called twice: both before and after inside layout. + // In the before pass, if it turns out we need the automatic height of the box, we abort these steps. + // This allows the box to retain an indefinite height from the perspective of inside layout. + auto margin_top = box.computed_values().margin().top(); auto margin_bottom = box.computed_values().margin().bottom(); auto top = box.computed_values().inset().top(); @@ -697,6 +701,10 @@ 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); @@ -748,6 +756,10 @@ 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(verify_cast(box))); @@ -766,6 +778,10 @@ 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(verify_cast(box))); @@ -893,10 +909,11 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava // NOTE: We compute height before *and* after doing inside layout. // This is done so that inside layout can resolve percentage heights. // In some situations, e.g with non-auto top & bottom values, the height can be determined early. - compute_height_for_absolutely_positioned_element(box, available_space); + compute_height_for_absolutely_positioned_element(box, available_space, BeforeOrAfterInsideLayout::Before); auto independent_formatting_context = layout_inside(box, LayoutMode::Normal, box_state.available_inner_space_or_constraints_from(available_space)); - compute_height_for_absolutely_positioned_element(box, available_space); + + compute_height_for_absolutely_positioned_element(box, available_space, BeforeOrAfterInsideLayout::After); box_state.margin_left = box.computed_values().margin().left().resolved(box, width_of_containing_block_as_length).to_px(box); box_state.margin_top = box.computed_values().margin().top().resolved(box, width_of_containing_block_as_length).to_px(box); @@ -966,7 +983,7 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava independent_formatting_context->parent_context_did_dimension_child_root_box(); } -void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(ReplacedBox const& box, AvailableSpace const& available_space) +void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(ReplacedBox const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout) { // 10.6.5 Absolutely positioned, replaced elements // The used value of 'height' is determined as for inline replaced elements. diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h index 1b74d88650..7e1692c8e0 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h @@ -110,9 +110,14 @@ protected: void compute_width_for_absolutely_positioned_element(Box const&, AvailableSpace const&); void compute_width_for_absolutely_positioned_non_replaced_element(Box const&, AvailableSpace const&); void compute_width_for_absolutely_positioned_replaced_element(ReplacedBox const&, AvailableSpace const&); - void compute_height_for_absolutely_positioned_element(Box const&, AvailableSpace const&); - void compute_height_for_absolutely_positioned_non_replaced_element(Box const&, AvailableSpace const&); - void compute_height_for_absolutely_positioned_replaced_element(ReplacedBox const&, AvailableSpace const&); + + enum class BeforeOrAfterInsideLayout { + Before, + After, + }; + void compute_height_for_absolutely_positioned_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout); + void compute_height_for_absolutely_positioned_non_replaced_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout); + void compute_height_for_absolutely_positioned_replaced_element(ReplacedBox const&, AvailableSpace const&, BeforeOrAfterInsideLayout); Type m_type {};