JSFiddle - React, Tailwind, and code Playground
Intersection Observer test with position announcement
by Travis Almand
HTML
<div id="container">
<div id="contained"></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="side">side to side</button>
<button id="up">up and down</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: flex;
height: 400px;
overflow: hidden;
justify-content: center;
width: 400px;
}
#contained {
background-color: rebeccapurple;
height: 200px;
width: 200px;
&.side {
animation: sidetoside 5s linear infinite alternate;
}
&.up {
animation: upanddown 5s linear infinite alternate;
}
}
#panel {
margin: 10px;
width: 400px;
.buttons {
margin: 10px 0;
}
}
@keyframes sidetoside {
0% {
transform: translate3d(-350px, 0, 0);
}
100% {
transform: translate3d(350px, 0, 0);
}
}
@keyframes upanddown {
0% {
transform: translate3d(0, -350px, 0);
}
100% {
transform: translate3d(0, 350px, 0);
}
}
JavaScript
console.clear();
let container = document.querySelector('#container');
let contained = document.querySelector('#contained');
let side = document.querySelector('#side');
let up = document.querySelector('#up');
let isIntersecting = document.querySelector('#intersecting span');
let intersectionRatio = document.querySelector('#ratio span');
let position = document.querySelector('#position span');
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);
side.addEventListener('click', function () {
contained.classList.remove('up');
contained.classList.toggle('side');
});
up.addEventListener('click', function () {
contained.classList.remove('side');
contained.classList.toggle('up');
});
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';
}
});
}