'Intersection observer does not work with target with position: fixed
I am trying to invoke a callback via intersection observer.
I want the target to be style: "position: fixed" and move it via
style.top.
I also specified the root element which is an ancestor of the target with style: "position: relative".
But when the target and the observer intersects, the callback function won't be triggered.
Are there some limitations I missed?
Here is what I typed:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>IO</title>
</head>
<body>
<div style="height: 200px;width: 100%;background: violet" class="upper">aaa</div>
<div style="position:relative;height: 200px;width: 100%;background: blueviolet" id="middle">bbb
<div id="target" style="position:fixed;top: 0px;width: 50px;height: 50px;background: firebrick">ccc</div>
</div>
<script>
let options = {
root: document.getElementById("middle"),
rootMargin: '0px',
threshold: 0
};
let observer = new IntersectionObserver(entry => {
console.log("observer's acting.")
}, options);
let target = document.getElementById("target");
observer.observe(target);
let stepping = 0;
let cb = () => {
target.style.top = stepping + 'px';
stepping += 4;
if (stepping < 300){
setTimeout(cb, 100);
}
};
window.addEventListener("click", () => {
cb();
})
</script>
</body>
</html>
And here is a codepen demo: codepen demo
You can click anywhere in the page to start moving the ccc block.
Solution 1:[1]
Elements with position: fixed are positioned relative to the viewport and the viewport moves. So, fixed positioned elements "move" as you scroll. Even though #target is a child of #middle, I believe the IntersectionObserver, with whatever it uses under the hood to calculate if the target is entering/leaving the root, never fires the callback because the target is outside of the document flow.
Here is a related issue. There isn't much out in the interwebs related to this issue: https://bugs.chromium.org/p/chromium/issues/detail?id=653240
Note: Setting position: absolute on the target does indeed fire the callback when entering and leaving the viewport.
Solution 2:[2]
In my case I had my root element (with position:fixed) at the same DOM hierarchy level as the elements I wanted to observe (that were scrollable) and no events were triggered.
<div id="root" style="position:fixed"></div>
<div id="scrollable"></div>
When I placed the elements inside the root the events triggered.
<div id="root" style="position:fixed">
<div id="scrollable"></div>
</div>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | snewcomer |
| Solution 2 | Jonathan |
