Files
ladybird/Tests/LibWeb/Text/input/IntersectionObserver/implicit-root-clips-at-scroll-container.html
Andreas Kling 229eba9a06 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).
2026-03-22 14:09:22 -05:00

48 lines
1.3 KiB
HTML

<!DOCTYPE html>
<style>
body { margin: 0; }
#scroller {
width: 200px;
height: 200px;
overflow: hidden;
}
#spacer {
height: 500px;
}
#target {
width: 50px;
height: 50px;
background: red;
}
</style>
<script src="../include.js"></script>
<div id="scroller">
<div id="spacer"></div>
<div id="target"></div>
</div>
<script>
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 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}: ratio=${entry.intersectionRatio}`);
});
if (callbackCount === 1) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
println(`total callbacks: ${callbackCount}`);
done();
});
});
}
});
observer.observe(document.getElementById("target"));
});
</script>