1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 03:17:35 +00:00

LibWeb: Narrow width of boxes that create BFC to avoid overlap of float

https://www.w3.org/TR/CSS22/visuren.html#floats says that when a box
establishes BFC it should not overlap with floats. The way to avoid
overlaps is up to implementor. This change implements avoiding overlap
by narrowing width of a box because it seems like what other engines
do (in the scenarios I tested).
This commit is contained in:
Aliaksandr Kalenik 2023-05-04 06:34:35 +03:00 committed by Andreas Kling
parent bf41af6b9d
commit 853ecb8d8e
3 changed files with 71 additions and 10 deletions

View file

@ -0,0 +1,22 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x1008 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x108.21875 children: not-inline
BlockContainer <div.wrapper> at (8,8) content-size 784x108.21875 children: not-inline
BlockContainer <div.float> at (592,8) content-size 200x1000 floating [BFC] children: not-inline
BlockContainer <div.bfc> at (18,18) content-size 564x88.21875 [BFC] children: inline
line 0 width: 458.125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 56, rect: [18,18 458.125x17.46875]
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."
line 1 width: 511.796875, height: 17.9375, bottom: 35.40625, baseline: 13.53125
frag 0 from TextNode start: 57, length: 60, rect: [18,35 511.796875x17.46875]
"Pellentesque vitae neque nunc. Nam fermentum libero a lectus"
line 2 width: 537.078125, height: 18.40625, bottom: 53.34375, baseline: 13.53125
frag 0 from TextNode start: 118, length: 67, rect: [18,52 537.078125x17.46875]
"vulputate eleifend. Nam sagittis tristique augue, id sodales mauris"
line 3 width: 537.34375, height: 17.875, bottom: 70.28125, baseline: 13.53125
frag 0 from TextNode start: 186, length: 65, rect: [18,70 537.34375x17.46875]
"suscipit at. Vivamus eget placerat ex. Suspendisse potenti. Morbi"
line 4 width: 455.375, height: 18.34375, bottom: 88.21875, baseline: 13.53125
frag 0 from TextNode start: 252, length: 57, rect: [18,87 455.375x17.46875]
"pulvinar ipsum eget nulla dapibus, ac varius mi eleifend."
TextNode <#text>

View file

@ -0,0 +1,23 @@
<style>
* {
font-family: 'SerenitySans';
}
.float {
width: 200px;
height: 1000px;
background-color: royalblue;
float: right;
}
.bfc {
background-color: mediumseagreen;
border: 10px solid skyblue;
display: flow-root;
}
</style>
<div class="wrapper"><div class="float"></div><div class="bfc">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vitae
neque nunc. Nam fermentum libero a lectus vulputate eleifend. Nam sagittis
tristique augue, id sodales mauris suscipit at. Vivamus eget placerat ex.
Suspendisse potenti. Morbi pulvinar ipsum eget nulla dapibus, ac varius mi
eleifend.

View file

@ -115,12 +115,28 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
return;
}
auto remaining_available_space = available_space;
if (available_space.width.is_definite() && creates_block_formatting_context(box)) {
// 9.5 Floats
// The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a
// new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin
// box of any floats in the same block formatting context as the element itself. If necessary, implementations should
// clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is
// sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3.
// CSS2 does not define when a UA may put said element next to the float or by how much said element may
// become narrower.
auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(box, root(), m_state);
auto space = space_used_by_floats(box_in_root_rect.y());
auto remaining_width = available_space.width.to_px() - space.left - space.right;
remaining_available_space.width = AvailableSize::make_definite(remaining_width);
}
if (is<ReplacedBox>(box)) {
// FIXME: This should not be done *by* ReplacedBox
auto& replaced = verify_cast<ReplacedBox>(box);
// FIXME: This const_cast is gross.
const_cast<ReplacedBox&>(replaced).prepare_for_replaced_layout();
compute_width_for_block_level_replaced_element_in_normal_flow(replaced, available_space);
compute_width_for_block_level_replaced_element_in_normal_flow(replaced, remaining_available_space);
// NOTE: We don't return here.
}
@ -131,8 +147,8 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
auto const& computed_values = box.computed_values();
auto width_of_containing_block = available_space.width.to_px();
auto width_of_containing_block_as_length_for_resolve = available_space.width.is_definite() ? CSS::Length::make_px(width_of_containing_block) : CSS::Length::make_px(0);
auto width_of_containing_block = remaining_available_space.width.to_px();
auto width_of_containing_block_as_length_for_resolve = remaining_available_space.width.is_definite() ? CSS::Length::make_px(width_of_containing_block) : CSS::Length::make_px(0);
auto zero_value = CSS::Length::make_px(0);
@ -216,10 +232,10 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
return CSS::Length::make_px(box_state.content_width());
}
if (is<TableWrapper>(box))
return CSS::Length::make_px(compute_width_for_table_wrapper(box, available_space));
if (should_treat_width_as_auto(box, available_space))
return CSS::Length::make_px(compute_width_for_table_wrapper(box, remaining_available_space));
if (should_treat_width_as_auto(box, remaining_available_space))
return CSS::Length::make_auto();
return calculate_inner_width(box, available_space.width, computed_values.width());
return calculate_inner_width(box, remaining_available_space.width, computed_values.width());
}();
// 1. The tentative used width is calculated (without 'min-width' and 'max-width')
@ -228,8 +244,8 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
// 2. The tentative used width is greater than 'max-width', the rules above are applied again,
// but this time using the computed value of 'max-width' as the computed value for 'width'.
if (!computed_values.max_width().is_none()) {
auto max_width = calculate_inner_width(box, available_space.width, computed_values.max_width());
auto used_width_px = used_width.is_auto() ? available_space.width.to_px() : used_width.to_px(box);
auto max_width = calculate_inner_width(box, remaining_available_space.width, computed_values.max_width());
auto used_width_px = used_width.is_auto() ? remaining_available_space.width.to_px() : used_width.to_px(box);
if (used_width_px > max_width.to_px(box)) {
used_width = try_compute_width(max_width);
}
@ -238,8 +254,8 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
// 3. If the resulting width is smaller than 'min-width', the rules above are applied again,
// but this time using the value of 'min-width' as the computed value for 'width'.
if (!computed_values.min_width().is_auto()) {
auto min_width = calculate_inner_width(box, available_space.width, computed_values.min_width());
auto used_width_px = used_width.is_auto() ? available_space.width.to_px() : used_width.to_px(box);
auto min_width = calculate_inner_width(box, remaining_available_space.width, computed_values.min_width());
auto used_width_px = used_width.is_auto() ? remaining_available_space.width.to_px() : used_width.to_px(box);
if (used_width_px < min_width.to_px(box)) {
used_width = try_compute_width(min_width);
}