[JS] Intersection Observer API
What’s the issue I spotted?
While browsing modern websites, I noticed a common yet impressive feature: as I scroll to specific sections, those sections animate into view, and the corresponding item in the navigation bar becomes highlighted.
This subtle interaction enhances the user experience dramatically. But that led me to wonder — how does the browser know when a section has entered the viewport?
Enter: Intersection Observer API
The Intersection Observer API provides a powerful, performant way to detect when elements intersect with the viewport or a parent container.
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.
In short: it lets us detect when an element comes into view without relying on heavy scroll event listeners.
Step-by-Step: How to Use It
✅ 1 - Define an observer
const options = {
root: null, // use the viewport as the root
rootMargin: "0px",
threshold: 0.1, // trigger when 10% of the element is visible
};
const observer = new IntersectionObserver(callback, options);
root: The element to use as the viewport for checking visibility (set tonullto use the browser viewport).rootMargin: Margin around the root. Can be used to grow or shrink the root bounding box.threshold: A number between 0 and 1 indicating when to trigger the callback (0.1 = 10% visible).
Mostly I just only set threshold while root will be defaulted to the whole viewport
✅ 2 - Create the Callback
const callback = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
// Optionally stop observing after first trigger
observer.unobserve(entry.target);
}
});
};
entries: An array of observed intersection changes.entry.isIntersecting: Boolean indicating whether the element is in view.observer.unobserve(entry.target): Stops observing the element after it's triggered once.
You can omit the second parameter if you're not using it, but it's handy for.unobserve()or.disconnect().
💡 Why should I useentry.targetrather thanentry?
We should be mindful that entry is actually an object which looks like below:
{
time: 263.5999999642372,
rootBounds: {...},
boundingClientRect: {...},
intersectionRect: {...},
isIntersecting: true,
intersectionRatio: 1,
target: HTMLElement ←✅ what you want!
}
✅ 3 — Apply to Your Elements
const faders = document.querySelectorAll(".fade-in-section");
faders.forEach(fader => {
Observer.observe(fader);
});
Any element with the fade-in class will now animate when it enters the viewport.
Comments ()