mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-26 01:35:08 +02:00
LibWeb: Clip against scroll containers in IntersectionObserver
Implement the containing block chain traversal in compute_intersection (steps 2-3 of the spec algorithm). Walk from the target's paintable box up through the containing block chain, clipping the intersection rect against each ancestor that has a content clip (overflow != visible). This fixes the case where a target is inside an overflow:hidden or overflow:clip container and pushed below the visible area. Previously, the intersection ratio was incorrectly non-zero because we only intersected with the root bounds (viewport), not intermediate scroll containers. Also update the scroll container clipping tests to verify the intersection ratio (which is what compute_intersection affects) rather than isIntersecting (which per spec is based on targetRect vs rootBounds, not the clipped intersection rect).
This commit is contained in:
committed by
Andreas Kling
parent
d1b485e6d6
commit
229eba9a06
Notes:
github-actions[bot]
2026-03-22 19:11:11 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/229eba9a069 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8574
@@ -23,12 +23,13 @@ body { margin: 0; }
|
||||
<script>
|
||||
asyncTest(done => {
|
||||
// The target is inside an overflow:clip container, pushed below
|
||||
// the visible area by a spacer. It should NOT be intersecting.
|
||||
// the visible area by a spacer. The intersection ratio should be 0
|
||||
// because compute_intersection clips against the container.
|
||||
let callbackCount = 0;
|
||||
let observer = new IntersectionObserver(entries => {
|
||||
callbackCount++;
|
||||
entries.forEach(entry => {
|
||||
println(`callback ${callbackCount}: isIntersecting=${entry.isIntersecting}`);
|
||||
println(`callback ${callbackCount}: ratio=${entry.intersectionRatio}`);
|
||||
});
|
||||
if (callbackCount === 1) {
|
||||
requestAnimationFrame(() => {
|
||||
|
||||
@@ -24,13 +24,13 @@ body { margin: 0; }
|
||||
asyncTest(done => {
|
||||
// The target is inside a scroll container with overflow:hidden.
|
||||
// The spacer pushes the target below the scroll container's visible area.
|
||||
// With the implicit root (viewport), the target should NOT be intersecting
|
||||
// because it is clipped by the scroll container.
|
||||
// With the implicit root (viewport), the intersection ratio should be 0
|
||||
// because compute_intersection clips against the scroll container.
|
||||
let callbackCount = 0;
|
||||
let observer = new IntersectionObserver(entries => {
|
||||
callbackCount++;
|
||||
entries.forEach(entry => {
|
||||
println(`callback ${callbackCount}: isIntersecting=${entry.isIntersecting}`);
|
||||
println(`callback ${callbackCount}: ratio=${entry.intersectionRatio}`);
|
||||
});
|
||||
if (callbackCount === 1) {
|
||||
requestAnimationFrame(() => {
|
||||
|
||||
Reference in New Issue
Block a user