mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:17:34 +00:00
LibWeb: Use offset of nearest scrollable ancestor for positioned boxes
Because positioned descendants are painted out-of-order we need to separately apply offset of nearest scrollable box for them. Fixes https://github.com/SerenityOS/serenity/issues/20554
This commit is contained in:
parent
2952f01e84
commit
6b79508c08
5 changed files with 167 additions and 0 deletions
|
@ -0,0 +1,73 @@
|
||||||
|
<html>
|
||||||
|
<link rel="match" href="reference/positioned-elements-in-scroll-container-ref.html" />
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
overflow-x: scroll;
|
||||||
|
overflow-y: scroll;
|
||||||
|
width: 500px;
|
||||||
|
height: 500px;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin: 2rem;
|
||||||
|
height: 30rem;
|
||||||
|
background-color: #bbb;
|
||||||
|
position: relative; /* is not positioned in the reference html */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<main>
|
||||||
|
<article id="scrollcontainer">
|
||||||
|
<h1>Fly away to victory!</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
|
||||||
|
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card">A card!</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
|
||||||
|
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
|
||||||
|
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
<script>
|
||||||
|
const scrollContainer = document.getElementById("scrollcontainer");
|
||||||
|
scrollContainer.scrollTop = 100;
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,71 @@
|
||||||
|
<html>
|
||||||
|
<link rel="match" href="reference/positioned-elements-in-scroll-container-ref.html" />
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
overflow-x: scroll;
|
||||||
|
overflow-y: scroll;
|
||||||
|
width: 500px;
|
||||||
|
height: 500px;
|
||||||
|
border: 1px solid black;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin: 2rem;
|
||||||
|
height: 30rem;
|
||||||
|
background-color: #bbb;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<main>
|
||||||
|
<article id="scrollcontainer">
|
||||||
|
<h1>Fly away to victory!</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
||||||
|
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
|
||||||
|
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
|
||||||
|
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||||
|
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
|
||||||
|
deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card">A card!</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
||||||
|
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
|
||||||
|
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
|
||||||
|
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||||
|
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
|
||||||
|
deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
||||||
|
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
|
||||||
|
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
|
||||||
|
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
|
||||||
|
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
|
||||||
|
deserunt mollit anim id est laborum.
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
<script>
|
||||||
|
const scrollContainer = document.getElementById("scrollcontainer");
|
||||||
|
scrollContainer.scrollTop = 100;
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -850,4 +850,15 @@ Optional<HitTestResult> PaintableWithLines::hit_test(CSSPixelPoint position, Hit
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PaintableBox const* PaintableBox::nearest_scrollable_ancestor() const
|
||||||
|
{
|
||||||
|
auto* ancestor = parent();
|
||||||
|
while (ancestor) {
|
||||||
|
if (ancestor->is_paintable_box() && static_cast<PaintableBox const*>(ancestor)->has_scrollable_overflow())
|
||||||
|
return static_cast<PaintableBox const*>(ancestor);
|
||||||
|
ancestor = ancestor->parent();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,8 @@ public:
|
||||||
BorderRadiiData const& border_radii_data() const { return m_border_radii_data; }
|
BorderRadiiData const& border_radii_data() const { return m_border_radii_data; }
|
||||||
void set_border_radii_data(BorderRadiiData const& border_radii_data) { m_border_radii_data = border_radii_data; }
|
void set_border_radii_data(BorderRadiiData const& border_radii_data) { m_border_radii_data = border_radii_data; }
|
||||||
|
|
||||||
|
PaintableBox const* nearest_scrollable_ancestor() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit PaintableBox(Layout::Box const&);
|
explicit PaintableBox(Layout::Box const&);
|
||||||
|
|
||||||
|
|
|
@ -226,6 +226,13 @@ void StackingContext::paint_internal(PaintContext& context) const
|
||||||
: TraversalDecision::Continue;
|
: TraversalDecision::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply scroll offset of nearest scrollable ancestor before painting the positioned descendant.
|
||||||
|
PaintableBox const* nearest_scrollable_ancestor = nullptr;
|
||||||
|
if (paintable.is_paintable_box())
|
||||||
|
nearest_scrollable_ancestor = static_cast<PaintableBox const&>(paintable).nearest_scrollable_ancestor();
|
||||||
|
if (nearest_scrollable_ancestor)
|
||||||
|
nearest_scrollable_ancestor->apply_scroll_offset(context, PaintPhase::Foreground);
|
||||||
|
|
||||||
// At this point, `paintable_box` is a positioned descendant with z-index: auto.
|
// At this point, `paintable_box` is a positioned descendant with z-index: auto.
|
||||||
// FIXME: This is basically duplicating logic found elsewhere in this same function. Find a way to make this more elegant.
|
// FIXME: This is basically duplicating logic found elsewhere in this same function. Find a way to make this more elegant.
|
||||||
auto exit_decision = TraversalDecision::Continue;
|
auto exit_decision = TraversalDecision::Continue;
|
||||||
|
@ -247,6 +254,9 @@ void StackingContext::paint_internal(PaintContext& context) const
|
||||||
if (containing_block_paintable)
|
if (containing_block_paintable)
|
||||||
containing_block_paintable->clear_clip_overflow_rect(context, PaintPhase::Foreground);
|
containing_block_paintable->clear_clip_overflow_rect(context, PaintPhase::Foreground);
|
||||||
|
|
||||||
|
if (nearest_scrollable_ancestor)
|
||||||
|
nearest_scrollable_ancestor->reset_scroll_offset(context, PaintPhase::Foreground);
|
||||||
|
|
||||||
return exit_decision;
|
return exit_decision;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue