mirror of
https://github.com/SerenityOS/serenity
synced 2024-09-06 08:56:40 +00:00
LibWeb: Handle case where abspos flex child position depends on height
There's a particularly awkward case where the static position of an abspos child of a flex container is dependent on its height. This can happen when `align-items: center` is in effect, as we have to adjust the abspos child's Y position by half of its height. This patch solves the issue by reordering operations in the abspos height resolution algorithm, to make sure that height is resolved before the static position is calculated.
This commit is contained in:
parent
f77256fcba
commit
50d72f0d8c
|
@ -0,0 +1,12 @@
|
|||
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 800x16 [BFC] children: not-inline
|
||||
Box <body> at (8,8) content-size 784x0 positioned flex-container(row) [FFC] children: not-inline
|
||||
BlockContainer <div.abspos> at (8,-42) content-size 100x100 positioned [BFC] children: not-inline
|
||||
BlockContainer <div.green> at (8,-42) content-size 100x200 children: inline
|
||||
TextNode <#text>
|
||||
|
||||
ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,-42 800x642]
|
||||
PaintableWithLines (BlockContainer<HTML>) [0,0 800x16] overflow: [0,-42 800x200]
|
||||
PaintableBox (Box<BODY>) [8,8 784x0] overflow: [8,-42 100x200]
|
||||
PaintableWithLines (BlockContainer<DIV>.abspos) [8,-42 100x100] overflow: [8,-42 100x200]
|
||||
PaintableWithLines (BlockContainer<DIV>.green) [8,-42 100x200]
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html><style>
|
||||
* { outline: black solid 1px; }
|
||||
body {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.abspos {
|
||||
position: absolute;
|
||||
max-height: 100px;
|
||||
}
|
||||
.green {
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 200px;
|
||||
background: green;
|
||||
}
|
||||
</style><body><div class="abspos"><div class="green">
|
|
@ -823,6 +823,21 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
|
|||
// 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 apply_min_max_height_constraints = [this, &box, &available_space](CSSPixels unconstrained_height) -> CSSPixels {
|
||||
auto const& computed_min_height = box.computed_values().min_height();
|
||||
auto const& computed_max_height = box.computed_values().max_height();
|
||||
auto constrained_height = unconstrained_height;
|
||||
if (!computed_max_height.is_none()) {
|
||||
auto inner_max_height = calculate_inner_height(box, available_space.height, computed_max_height);
|
||||
constrained_height = min(constrained_height, inner_max_height.to_px(box));
|
||||
}
|
||||
if (!computed_min_height.is_auto()) {
|
||||
auto inner_min_height = calculate_inner_height(box, available_space.height, computed_min_height);
|
||||
constrained_height = max(constrained_height, inner_min_height.to_px(box));
|
||||
}
|
||||
return constrained_height;
|
||||
};
|
||||
|
||||
auto margin_top = box.computed_values().margin().top();
|
||||
auto margin_bottom = box.computed_values().margin().bottom();
|
||||
auto top = box.computed_values().inset().top();
|
||||
|
@ -888,14 +903,22 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
|
|||
margin_bottom = CSS::Length::make_px(0);
|
||||
|
||||
// then set top to the static position,
|
||||
auto static_position = calculate_static_position(box);
|
||||
top = CSS::Length::make_px(static_position.y());
|
||||
|
||||
// and finally apply rule number three below.
|
||||
|
||||
// NOTE: We actually perform these two steps in the opposite order,
|
||||
// because the static position may depend on the height of the box (due to alignment properties).
|
||||
|
||||
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());
|
||||
|
||||
auto constrained_height = apply_min_max_height_constraints(maybe_height.value());
|
||||
m_state.get_mutable(box).set_content_height(constrained_height);
|
||||
|
||||
auto static_position = calculate_static_position(box);
|
||||
top = CSS::Length::make_px(static_position.y());
|
||||
|
||||
solve_for_bottom();
|
||||
}
|
||||
|
||||
|
@ -993,17 +1016,8 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
|
|||
} else {
|
||||
used_height = calculate_inner_height(box, available_space.height, height).to_px(box);
|
||||
}
|
||||
auto const& computed_min_height = box.computed_values().min_height();
|
||||
auto const& computed_max_height = box.computed_values().max_height();
|
||||
|
||||
if (!computed_max_height.is_none()) {
|
||||
auto inner_max_height = calculate_inner_height(box, available_space.height, computed_max_height);
|
||||
used_height = min(used_height, inner_max_height.to_px(box));
|
||||
}
|
||||
if (!computed_min_height.is_auto()) {
|
||||
auto inner_min_height = calculate_inner_height(box, available_space.height, computed_min_height);
|
||||
used_height = max(used_height, inner_min_height.to_px(box));
|
||||
}
|
||||
used_height = apply_min_max_height_constraints(used_height);
|
||||
|
||||
// NOTE: The following is not directly part of any spec, but this is where we resolve
|
||||
// the final used values for vertical margin/border/padding.
|
||||
|
|
Loading…
Reference in a new issue