As a web developer, you often need to implement features that depend on elements being visible in the viewport, such as lazy loading images or infinite scrolling. However, checking the intersection of elements using traditional methods like getBoundingClientRect
can be slow and resource-intensive, especially if you have a large number of elements to monitor.
That’s where Intersection Observer comes in. Intersection Observer is a JavaScript API that allows you to efficiently monitor changes in the intersection between an element and its ancestor elements or the viewport. It’s designed to be performant and can be used to monitor a large number of elements without causing performance issues.
In this article, we’ll take a deep dive into Intersection Observer and learn how it works. You’ll learn how to create an Intersection Observer instance, observe elements, and use the API to implement features like lazy loading and infinite scrolling. By the end of this article, you’ll have a solid understanding of how Intersection Observer can help you improve the performance and functionality of your web applications.
Creating an Intersection Observer instance
To create an Intersection Observer instance, you can use the following code:
const observer = new IntersectionObserver(callback, options);
The callback
function is called when the intersection of an element changes. It receives an array of IntersectionObserverEntry
objects as an argument, which contain information about the intersection of the element.
The options
object allows you to specify additional settings for the Intersection Observer, such as the root element to use for intersection calculations and the threshold at which the callback function should be called.
For example, you can use the root
option to specify that the intersection should be calculated with respect to a specific ancestor element instead of the viewport:
const observer = new IntersectionObserver(callback, { root: document.querySelector('#scrollable-area') });
You can also use the threshold
option to specify the percentage of the element that should be visible before the callback function is called. The threshold
option can be a single value or an array of values. If it's an array, the callback function will be called for each threshold that is crossed.
For example, the following code will call the callback function when 50% of the element is visible:
const observer = new IntersectionObserver(callback, { threshold: 0.5 });
Observing elements
Once you’ve created an Intersection Observer instance, you can start observing elements by calling the observe
method:
observer.observe(element);
The observe
method takes an element as an argument and starts monitoring its intersection with the viewport or the root element. The callback function will be called whenever the intersection changes.
You can also stop observing an element by calling the unobserve
method:
observer.unobserve(element);
This can be useful if you no longer need to monitor the intersection of an element, for example if you’ve already loaded the resources that were lazy-loaded using Intersection Observer.
Disconnecting the Intersection Observer
Finally, you can stop the Intersection Observer from monitoring any elements by calling the disconnect
method:
observer.disconnect();
This can be useful if you no longer need the Intersection Observer and want to free up resources.
Lazy loading images
Although now you can lazy-load your images with only HTML, before that IntersectionObserver was commonly used to tackle this problem. In this example you’ll see how lazy-loading can be achieved in a React component.
First we create an Intersection Observer instance and pass it a callback function that sets the src
attribute of the image element when it becomes visible in the viewport. We also use the useEffect
hook to start observing the image element when the component mounts.
import React, { useRef, useEffect } from 'react';
function LazyImage({ src, alt }) {
const imageRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = src;
observer.unobserve(img);
}
});
});
observer.observe(imageRef.current);
}, [src]);
return <img ref={imageRef} alt={alt} />;
}
Infinite scroll
Whenever you are browsing a site where content keeps appearing from nowhere without you clicking any button, this mechanism is being used.
Let’s start again with creating an Intersection Observer instance and pass it a callback function that calls the loadMore
function when the bottom of the list becomes visible in the viewport. We also use the useEffect
hook to start observing the list element when the component mounts.
When the loadMore
function is called, it can fetch more items from a server or database and add them to the list. This allows the list to load additional items as the user scrolls down, creating the illusion of an infinite scroll.
import React, { useRef, useEffect } from 'react';
function InfiniteScrollList({ items, loadMore }) {
const listRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
loadMore();
}
});
});
observer.observe(listRef.current);
}, [loadMore]);
return (
<ul ref={listRef}>
{items.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}
I hope this article has helped you understand how Intersection Observer works and how you can use it in your web applications. If you have any questions or need further clarification, don’t hesitate to ask!