layout: Do not include position:fixed children when calculating scrollable overflow for root element (#38618)

Reimplementation of: #35931

For a `FragmentTree` we define a scrollable overflow calculation that
includes the overflow all of it's children `Fragments`. In practice we
are using this calculation for scrolling area of the viewport and
defining the root scroll frames. However, since uncontained fixed
positioned element is located outside of the document and should not be
scrolled, and therefore it would make no sense to include them in the
calculation of its scrollable overflow as well.

Testing: New and existing WPT tests
Fixes: #38617
Fixes: #38182

---------

Signed-off-by: Jo Steven Novaryo <jo.steven.novaryo@huawei.com>
This commit is contained in:
Jo Steven Novaryo 2025-08-18 19:25:31 +08:00 committed by GitHub
parent 7dcd89a6f9
commit 7489a0349f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 58 additions and 5 deletions

View file

@ -10,6 +10,7 @@ use compositing_traits::display_list::AxesScrollSensitivity;
use fxhash::FxHashSet;
use malloc_size_of_derive::MallocSizeOf;
use style::animation::AnimationSetKey;
use style::computed_values::position::T as Position;
use super::{BoxFragment, ContainingBlockManager, Fragment};
use crate::ArcRefCell;
@ -124,9 +125,26 @@ impl FragmentTree {
let scrollable_overflow = self.root_fragments.iter().fold(
self.initial_containing_block,
|overflow, fragment| {
fragment
.calculate_scrollable_overflow_for_parent()
.union(&overflow)
// Need to calculate the overflow for each fragments within the tree
// because it is required in the next stages of reflow.
let overflow_from_fragment =
fragment.calculate_scrollable_overflow_for_parent();
// Scrollable overflow should be accumulated in the block that
// establishes the containing block for the element. Thus, fixed
// positioned fragments whose containing block is the initial
// containing block should not be included in overflow calculation.
// See <https://www.w3.org/TR/css-overflow-3/#scrollable>.
if fragment
.retrieve_box_fragment()
.is_some_and(|box_fragment| {
box_fragment.borrow().style.get_box().position == Position::Fixed
})
{
return overflow;
}
overflow.union(&overflow_from_fragment)
},
);

View file

@ -607585,6 +607585,13 @@
}
]
],
"scrollable-overflow-fixed-positioned-initial-containing-block.html": [
"10f115a012a85230a4641a1d793c0a6df0db2e78",
[
null,
{}
]
],
"scrollable-overflow-float.html": [
"f75c0a66cfffdfe9872c6e472966ee3cf639eae6",
[

View file

@ -1,2 +0,0 @@
[clip-path-fixed-scroll.html]
expected: FAIL

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>Scrollable overflow of Document element with 'position: fixed' which has ICB as containing block</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#scrollable">
<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth">
<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-element-scrollheight">
<link rel="author" title="Jo Steven Novaryo" href="mailto:jo.steven.novaryo@huawei.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
</body>
<script>
promise_test(async (t) => {
let initialScrollHeight = document.scrollingElement.scrollHeight;
let initialScrollWidth = document.scrollingElement.scrollWidth;
let fixedDiv = document.createElement("div");
fixedDiv.style.position = "fixed";
fixedDiv.style.height = (initialScrollHeight * 2) + "px";
fixedDiv.style.width = (initialScrollWidth * 2) + "px";
document.body.appendChild(fixedDiv);
assert_equals(document.scrollingElement.scrollHeight, initialScrollHeight);
assert_equals(document.scrollingElement.scrollWidth, initialScrollWidth);
}, "position: fixed fixed with ICB as CB should not affect scrollable overflow of Document element.");
</script>
</html>