JSFiddle - React, Tailwind, and code Playground
Intersection Observer test: scrolling with position announcement
by Travis Almand
HTML
<div id="container">
<div id="scroller">
<div id="contained"></div>
</div>
</div>
<div id="panel">
<div id="intersecting">isIntersecting: <span></span></div>
<div id="ratio">intersection ratio: <span></span></div>
<div id="position">position: <span></span></div>
<div class="buttons">
<button id="reset">reset</button>
<button id="horizontal">horizontal</button>
<button id="vertical">vertical</button>
</div>
</div>
SCSS
body {
align-items: center;
background-color: #E0E0E0;
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
justify-content: center;
}
#container {
align-items: center;
background-color: #fff;
border: 3px solid rebeccapurple;
display: block;
height: 400px;
overflow: auto;
justify-content: center;
width: 400px;
&.horizontal #scroller {
height: 200px;
margin-top: 100px;
width: 1200px;
}
&.vertical #scroller {
height: 1200px;
margin-left: 100px;
width: 200px;
}
}
#scroller {
align-items: center;
display: flex;
height: 400px;
justify-content: center;
width: 400px;
}
#contained {
background-color: rebeccapurple;
height: 200px;
width: 200px;
}
#panel {
margin: 10px;
width: 400px;
.buttons {
margin: 10px 0;
}
}
JavaScript
console.clear();
let container = document.querySelector('#container');
let contained = document.querySelector('#contained');
let isIntersecting = document.querySelector('#intersecting span');
let intersectionRatio = document.querySelector('#ratio span');
let position = document.querySelector('#position span');
let reset = document.querySelector('#reset');
let horizontal = document.querySelector('#horizontal');
let vertical = document.querySelector('#vertical');
let threshold = [...Array(100).keys()].map(x => x / 100);
let options = {
root: container,
rootMargin: '0px',
threshold: threshold
}
let observer = new IntersectionObserver(callback, options);
observer.observe(contained);
reset.addEventListener('click', function () {
container.classList.remove('horizontal', 'vertical');
});
horizontal.addEventListener('click', function () {
container.classList.add('horizontal');
container.classList.remove('vertical');
});
vertical.addEventListener('click', function () {
container.classList.remove('horizontal');
container.classList.add('vertical');
});
function callback (entries, observer) {
entries.forEach(entry => {
let ratio = entry.intersectionRatio;
let boundingRect = entry.boundingClientRect;
let intersectionRect = entry.intersectionRect;
isIntersecting.innerText = entry.isIntersecting;
intersectionRatio.innerText = entry.intersectionRatio;
if (ratio === 0) {
position.innerText = 'outside';
} else if (ratio < 0.99) {
if (boundingRect.left < intersectionRect.left) {
position.innerText = 'on the left';
} else if (boundingRect.right > intersectionRect.right) {
position.innerText = 'on the right';
} else if (boundingRect.top < intersectionRect.top) {
position.innerText = 'on the top';
} else {
position.innerText = 'on the bottom';
}
} else {
position.innerText = 'inside';
}
});
}