1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:47:37 +00:00

LibWeb: Make sure that margins don't collapse across a nested BFC

In order to fix this, I also had to reorganize the code so that we
create an independent formatting context even for block-level boxes
that don't have any children. This accidentally improves a table
layout test as well (for empty tables).
This commit is contained in:
Andreas Kling 2023-05-19 13:48:47 +02:00
parent 9ce7681ff2
commit 411b28fc59
4 changed files with 62 additions and 31 deletions

View file

@ -0,0 +1,6 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x116 [BFC] children: not-inline
BlockContainer <body> at (8,30) content-size 784x100 children: not-inline
BlockContainer <div.not-bfc> at (8,30) content-size 784x20 children: not-inline
BlockContainer <div.bfc> at (8,80) content-size 784x0 [BFC] children: not-inline
BlockContainer <div.not-bfc> at (8,110) content-size 784x20 children: not-inline

View file

@ -1,8 +1,8 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x58.40625 children: not-inline BlockContainer <body> at (8,8) content-size 784x58.40625 children: not-inline
TableWrapper <(anonymous)> at (8,8) content-size 784x0 [BFC] children: not-inline TableWrapper <(anonymous)> at (8,8) content-size 0x0 [BFC] children: not-inline
TableBox <table#empty-table> at (8,8) content-size 784x0 [TFC] children: not-inline TableBox <table#empty-table> at (8,8) content-size 0x0 [TFC] children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text> TextNode <#text>
TextNode <#text> TextNode <#text>

View file

@ -0,0 +1,20 @@
<!doctype html><style>
* {
padding: 0;
}
html {
background: white;
}
body {
background: pink;
}
.not-bfc {
margin-top: 30px;
height: 20px;
background: orange;
}
.bfc {
margin-top: 30px;
display: flow-root;
}
</style><div class="not-bfc"></div><div class=bfc></div><div class="not-bfc"></div>

View file

@ -552,14 +552,24 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
m_margin_state.reset(); m_margin_state.reset();
} }
CSSPixels margin_top = 0;
auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, box);
if (independent_formatting_context) {
// Margins of elements that establish new formatting contexts do not collapse with their in-flow children
m_margin_state.reset();
margin_top = box_state.margin_top;
} else {
m_margin_state.add_margin(box_state.margin_top); m_margin_state.add_margin(box_state.margin_top);
m_margin_state.update_block_waiting_for_final_y_position(); m_margin_state.update_block_waiting_for_final_y_position();
auto margin_top = m_margin_state.current_collapsed_margin(); margin_top = m_margin_state.current_collapsed_margin();
if (m_margin_state.has_block_container_waiting_for_final_y_position()) { 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 // If first child margin top will collapse with margin-top of containing block then margin-top of child is 0
margin_top = 0; margin_top = 0;
} }
}
place_block_level_element_in_normal_flow_vertically(box, y + margin_top); place_block_level_element_in_normal_flow_vertically(box, y + margin_top);
@ -567,15 +577,11 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
place_block_level_element_in_normal_flow_horizontally(box, available_space); place_block_level_element_in_normal_flow_horizontally(box, available_space);
OwnPtr<FormattingContext> independent_formatting_context;
if (!box.is_replaced_box() && box.has_children()) {
independent_formatting_context = create_independent_formatting_context_if_needed(m_state, box);
if (independent_formatting_context) { if (independent_formatting_context) {
// Margins of elements that establish new formatting contexts do not collapse with their in-flow children // This box establishes a new formatting context. Pass control to it.
m_margin_state.reset();
independent_formatting_context->run(box, layout_mode, box_state.available_inner_space_or_constraints_from(available_space)); independent_formatting_context->run(box, layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
} else { } else {
// This box participates in the current block container's flow.
if (box.children_are_inline()) { if (box.children_are_inline()) {
layout_inline_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space)); layout_inline_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
} else { } else {
@ -592,11 +598,10 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space)); layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
} }
} }
}
compute_height(box, available_space); compute_height(box, available_space);
if (!margins_collapse_through(box, m_state)) { if (independent_formatting_context || !margins_collapse_through(box, m_state)) {
if (!m_margin_state.box_last_in_flow_child_margin_bottom_collapsed) { if (!m_margin_state.box_last_in_flow_child_margin_bottom_collapsed) {
m_margin_state.reset(); m_margin_state.reset();
} }