'Using intersectionObserver instead of onscroll event
my-div element has position absolute. When you scroll the page, as soon as my-div is out of the view port its position changes to fixed and top: 0. Here I need to change the value 0 for top to 100px.
I managed to do so by using onscroll method as follow:
document.onscroll = function(){
const myDiv = document.querySelector('.my-div')
if(myDiv && myDiv.style.position == 'fixed') {
myDiv.style.top = '100px';
}
}
The above code is working. However, the problem with this code is that it fires on each scroll event and is bad for performance. Now I'm trying to use intersectionObserver method instead of onscroll method.
What I need is: As soon as my-div isn't in the viewport and its position is fixed, add top 100px to it.
I tried this:
const myDiv = document.querySelector('.my-div');
if (myDiv) {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting === false && myDiv.style.position == 'fixed') {
myDiv.style.top = '100px';
observer.unobserve(entry.target);
}
});
});
observer.observe(myDiv);
}
But it's not working.
Solution 1:[1]
If you want to check if an entry is no longer in viewport, use .intersectionRatio property, if the value is 0 then it's not in the viewport:
if (entries[0].intersectionRatio <= 0) {
In the example below, scroll down and once the red square is no longer in viewport, it will be stuck at 100px from the top of viewport. Also added a semi-transparent background to serve as a easily noticeable style that confirms that the code functions as requested (ie change styles of a <div> once it is no longer within the viewport).
const X = document.querySelector('.X');
const obr = new IntersectionObserver(function(entries) {
if (entries[0].intersectionRatio <= 0) {
X.style.cssText = `position: fixed; top: 100px; background: rgba(255, 36, 0, 0.3)`;
this.unobserve(X);
}
});
obr.observe(X);
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0
}
html,
body {
width: 100%;
min-height: 100%
}
html {
font: 5vmax/1.375 Consolas;
scroll-behavior: smooth;
}
main {
position: relative;
width: 100vw;
height: 300vh;
overflow-y: scroll;
}
.X {
position: absolute;
top: calc(50vh - 2.25rem);
left: calc(50% - 2.25rem);
z-index: 1;
width: 4.5rem;
height: 4.5rem;
border: 5px groove tomato;
border-radius: 0.5rem;
text-align: center;
}
a {
display: inline-block;
position: absolute;
width: max-content;
margin: 0 5px;
font-size: 1.5rem;
}
#top {
top: 0;
right: 0;
}
#top+a {
top: 0;
left: 0
}
#mid {
top: calc(150vh - 2.25rem);
left: calc(50% - 2.25rem);
width: 4.5rem;
height: 4.5rem;
font-size: 3rem;
}
#mid+a {
bottom: 0;
left: 0
}
#sub {
bottom: 0;
right: 0;
}
<main>
<a href='#sub' id='top'>SUB</a>
<a href='#mid'>MID</a>
<div class='X'></div>
<a id='mid'>?</a>
<a href='#mid'>MID</a>
<a href='#top' id='sub'>TOP</a>
</main>
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 |
