mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
LibWeb: Margin top collapsing between parent and first child
Implement collapsing of a box margin-top and first in-flow child margin-top by saving function that updates y position of containing block inside BlockMarginState and then for every child until "non-collapsed through" child is reached y position of containing block is updated by calling update_box_waiting_fox_final_y_position_callback.
This commit is contained in:
parent
fe8304d5de
commit
7088a87f49
Notes:
sideshowbarker
2024-07-17 16:23:55 +09:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/SerenityOS/serenity/commit/7088a87f49 Pull-request: https://github.com/SerenityOS/serenity/pull/16632 Reviewed-by: https://github.com/awesomekling
3 changed files with 70 additions and 3 deletions
22
Base/res/html/misc/margin-collapse-3.html
Normal file
22
Base/res/html/misc/margin-collapse-3.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<style>
|
||||
#foo {
|
||||
background-color: red;
|
||||
margin-bottom: 25px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
#bar {
|
||||
background-color: green;
|
||||
margin-top: 100px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
#baz {
|
||||
background-color: blue;
|
||||
width: 100px;
|
||||
margin-top: -50px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
<div id=foo></div>
|
||||
<div id=bar><div id=baz></div></div>
|
|
@ -372,7 +372,8 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
|||
return;
|
||||
|
||||
if (box.is_floating()) {
|
||||
layout_floating_box(box, block_container, layout_mode, available_space, m_margin_state.current_collapsed_margin() + current_y);
|
||||
auto margin_top = !m_margin_state.has_block_container_waiting_for_final_y_position() ? m_margin_state.current_collapsed_margin() : 0;
|
||||
layout_floating_box(box, block_container, layout_mode, available_space, margin_top + current_y);
|
||||
bottom_of_lowest_margin_box = max(bottom_of_lowest_margin_box, box_state.offset.y() + box_state.content_height() + box_state.margin_box_bottom());
|
||||
return;
|
||||
}
|
||||
|
@ -383,8 +384,18 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
|||
compute_height(box, available_space);
|
||||
}
|
||||
|
||||
if (box.computed_values().clear() != CSS::Clear::None) {
|
||||
m_margin_state.reset();
|
||||
}
|
||||
|
||||
m_margin_state.add_margin(box_state.margin_top);
|
||||
m_margin_state.update_block_waiting_for_final_y_position();
|
||||
|
||||
auto margin_top = m_margin_state.current_collapsed_margin();
|
||||
if (m_margin_state.has_block_container_waiting_for_final_y_position()) {
|
||||
// If first child margin top will collapse with margin-top of containing block then margin-top of child is 0
|
||||
margin_top = 0;
|
||||
}
|
||||
|
||||
place_block_level_element_in_normal_flow_vertically(box, current_y + box_state.border_box_top() + margin_top);
|
||||
place_block_level_element_in_normal_flow_horizontally(box, available_space);
|
||||
|
@ -401,7 +412,16 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
|||
if (box.children_are_inline()) {
|
||||
layout_inline_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
||||
} else {
|
||||
m_margin_state.reset();
|
||||
if (box_state.border_top > 0 || box_state.padding_top > 0) {
|
||||
// margin-top of block container can't collapse with it's children if it has non zero border or padding
|
||||
m_margin_state.reset();
|
||||
} else if (!m_margin_state.has_block_container_waiting_for_final_y_position()) {
|
||||
// margin-top of block container can be updated during children layout hence it's final y position yet to be determined
|
||||
m_margin_state.register_block_container_y_position_update_callback([&](float margin_top) {
|
||||
place_block_level_element_in_normal_flow_vertically(box, margin_top + current_y + box_state.border_box_top());
|
||||
});
|
||||
}
|
||||
|
||||
layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
||||
}
|
||||
}
|
||||
|
@ -415,6 +435,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
|||
}
|
||||
|
||||
m_margin_state.add_margin(box_state.margin_bottom);
|
||||
m_margin_state.update_block_waiting_for_final_y_position();
|
||||
|
||||
compute_inset(box);
|
||||
|
||||
|
@ -440,7 +461,11 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer const& b
|
|||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
// FIXME: margin-bottom of last in-flow child can be collapsed with margin-bottom of parent
|
||||
// FIXME: The bottom margin of an in-flow block box with a 'height' of 'auto' collapses with its last in-flow block-level child's bottom margin, if:
|
||||
// the box has no bottom padding, and
|
||||
// the box has no bottom border, and
|
||||
// the child's bottom margin neither collapses with a top margin that has clearance, nor (if the box's min-height is non-zero) with the box's top margin.
|
||||
// https://www.w3.org/TR/CSS22/box.html#collapsing-margins
|
||||
m_margin_state.reset();
|
||||
|
||||
if (layout_mode == LayoutMode::IntrinsicSizing) {
|
||||
|
|
|
@ -113,16 +113,36 @@ private:
|
|||
|
||||
struct BlockMarginState {
|
||||
Vector<float> current_collapsible_margins;
|
||||
Function<void(float)> block_container_y_position_update_callback;
|
||||
|
||||
void add_margin(float margin)
|
||||
{
|
||||
current_collapsible_margins.append(margin);
|
||||
}
|
||||
|
||||
void register_block_container_y_position_update_callback(Function<void(float)> callback)
|
||||
{
|
||||
block_container_y_position_update_callback = move(callback);
|
||||
}
|
||||
|
||||
float current_collapsed_margin() const;
|
||||
|
||||
bool has_block_container_waiting_for_final_y_position() const
|
||||
{
|
||||
return static_cast<bool>(block_container_y_position_update_callback);
|
||||
}
|
||||
|
||||
void update_block_waiting_for_final_y_position() const
|
||||
{
|
||||
if (block_container_y_position_update_callback) {
|
||||
float collapsed_margin = current_collapsed_margin();
|
||||
block_container_y_position_update_callback(collapsed_margin);
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
block_container_y_position_update_callback = {};
|
||||
current_collapsible_margins.clear();
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue