I'm completely flummoxed by the rootMargin
property of intersection observer.
My goal is to add a class to an element when half it's height has crossed the vertical center of the viewport.
In my current project, nothing I do seems to impact the "root intersection rectangle" and the class is always added immediately. I've tested in latest Chrome and Firefox.
Here's the reduced test case:
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
const options = {
root: null, // default, use viewport
rootMargin: '0px 0px -50% 0px',
threshold: 0.5 // half of item height
}
const circle = document.getElementById('circle');
const observerCallback = function(entries, observer) {
console.log('intersected');
circle.classList.add('intersected');
}
window.addEventListener('load', function(event) {
const observer = new IntersectionObserver(observerCallback, options);
observer.observe(circle);
}, false);
.circle {
margin: 100vh auto;
width: 200px;
height: 200px;
background-color: tomato;
border-radius: 50%;
transition: background-color 2s ease-in-out;
}
.circle.intersected {
background-color: mediumseagreen;
}
<div class="circle" id="circle"></div>
The IntersectionObserver interface's read-only rootMargin property is a string with syntax similar to that of the CSS margin property. Each side of the rectangle represented by rootMargin is added to the corresponding side in the root element's bounding box before the intersection test is performed.
Thresholds. Rather than reporting every infinitesimal change in how much a target element is visible, the Intersection Observer API uses thresholds. When you create an observer, you can provide one or more numeric values representing percentages of the target element which are visible.
The IntersectionObserver interface of the Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. The ancestor element or viewport is referred to as the root.
To use the <InView> component, you pass it a function. It will be called whenever the state changes, with the new value of inView . In addition to the inView prop, children also receive a ref that should be set on the containing DOM element. This is the element that the Intersection Observer will monitor.
I am quite perplexed by IntersectionObserver myself sometimes, but referring to this post, it was a lot easier to grasp for me.
What was probably giving you trouble was checking for if it actually was intersecting or not. So I added an if-statement along with the property isIntersecting
that is found on IntersectionObserver entries.
I also added a check for IntersectionObserver if it is available on the client and removed root: null
from the options as it should default to the viewport anyway.
If you only use this IntersectionObserver for adding a class once, don't forget to observer.unobserve(circle)
or observer.disconnect()
when it isn't needed anymore to prevent memory leaks.
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
const options = {
rootMargin: '0px 0px -50% 0px',
threshold: 0.5 // half of item height
}
const circle = document.getElementById('circle');
const observer = new IntersectionObserver(entries => {
const [{ isIntersecting }] = entries
if (isIntersecting) {
console.log('intersected');
circle.classList.add('intersected');
} else {
console.log('not-intersecting');
}
}, options);
window.addEventListener('load', () => {
if ('IntersectionObserver' in window) observer.observe(circle);
}, false);
.circle {
margin: 100vh auto;
width: 200px;
height: 200px;
background-color: tomato;
border-radius: 50%;
transition: background-color 2s ease-in-out;
}
.circle.intersected {
background-color: mediumseagreen;
}
<div class="circle" id="circle"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With