mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-19 15:43:20 +00:00
LibWeb: Correctly calculate nested positioned elements' static position
If there are multiple nested `position: fixed` or `position: absolute` elements that are positioned based on their static position due to not specifying any insets, we sum up all their ancestor offsets to calculate said static position. However, these offsets represent the offset to the containing block. So summing up all the ancestor blocks will count elements multiple times for cases where the containing block is not based on the closest element capable of forming a containing block (i.e. absolute and fixed position elements) when multiple such elements are nested. With this change we only iterate over ancestors forming containing blocks instead of over all ancestors boxes. To sum up everything between the box currently being positioned and its containing block, we start the iteration on the parent box of the current box. This fixes 3 WPT tests that I could find. But these tests are not intended to test the error cases fixed here, they just incidentally rely on the correct behavior. As such, I have added dedicated tests myself. Note that two of the tests already pass on master, but they seemed like a good cases to have anyway.
This commit is contained in:
parent
0e4450f4b3
commit
70c46e081d
Notes:
github-actions[bot]
2025-10-14 08:24:45 +00:00
Author: https://github.com/InvalidUsernameException
Commit: 70c46e081d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6451
6 changed files with 95 additions and 2 deletions
|
@ -1167,13 +1167,15 @@ CSSPixelRect FormattingContext::content_box_rect_in_static_position_ancestor_coo
|
|||
{
|
||||
auto box_used_values = m_state.get(box);
|
||||
CSSPixelRect rect = { { 0, 0 }, box_used_values.content_size() };
|
||||
for (auto const* current = &box; current; current = current->static_position_containing_block()) {
|
||||
VERIFY(box_used_values.offset.is_zero()); // Set as result of this calculation
|
||||
for (auto const* current = box.static_position_containing_block(); current; current = current->containing_block()) {
|
||||
if (current == &ancestor_box)
|
||||
return rect;
|
||||
auto const& current_state = m_state.get(*current);
|
||||
rect.translate_by(current_state.offset);
|
||||
}
|
||||
// If we get here, ancestor_box was not an ancestor of `box`!
|
||||
// If we get here, `ancestor_box` was not in the containing block chain of the static position containing block of `box`!
|
||||
// Something about the containing block chain is set up incorrectly then.
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
div {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/position-absolute-fixed-nested-static-position.html" />
|
||||
<style>
|
||||
div {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
.absolute { position: absolute; }
|
||||
.fixed { position: fixed; }
|
||||
.outside { background-color: red; }
|
||||
.inside { background-color: orange; }
|
||||
.deep { background-color: yellow; }
|
||||
.deeper { background-color: green; }
|
||||
</style>
|
||||
<div class="outside">
|
||||
<div class="fixed inside">
|
||||
<div class="deep">
|
||||
<div class="absolute deeper"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/position-absolute-fixed-nested-static-position.html" />
|
||||
<style>
|
||||
div {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
.absolute { position: absolute; }
|
||||
.outside { background-color: red; }
|
||||
.inside { background-color: orange; }
|
||||
.deep { background-color: yellow; }
|
||||
.deeper { background-color: green; }
|
||||
</style>
|
||||
<div class="outside">
|
||||
<div class="absolute inside">
|
||||
<div class="deep">
|
||||
<div class="absolute deeper"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/position-absolute-fixed-nested-static-position.html" />
|
||||
<style>
|
||||
div {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
.absolute { position: absolute; }
|
||||
.fixed { position: fixed; }
|
||||
.outside { background-color: red; }
|
||||
.inside { background-color: orange; }
|
||||
.deep { background-color: yellow; }
|
||||
.deeper { background-color: green; }
|
||||
</style>
|
||||
<div class="outside">
|
||||
<div class="absolute inside">
|
||||
<div class="deep">
|
||||
<div class="fixed deeper"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="match" href="../expected/position-absolute-fixed-nested-static-position.html" />
|
||||
<style>
|
||||
div {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
.fixed { position: fixed; }
|
||||
.outside { background-color: red; }
|
||||
.inside { background-color: orange; }
|
||||
.deep { background-color: yellow; }
|
||||
.deeper { background-color: green; }
|
||||
</style>
|
||||
<div class="fixed outside">
|
||||
<div class="fixed inside">
|
||||
<div class="fixed deep">
|
||||
<div class="fixed deeper"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Add table
Add a link
Reference in a new issue