JavaScript Intersection Observer
Learn about JavaScript's Intersection Observer API including why the Intersection Observer API was created and how to use it.
Table of Contents 📖
- What is the Intersection Observer API?
- Why was the Intersection Observer API Created?
- IntersectionObserver Target and Root
- IntersectionObserver Object
What is the Intersection Observer API?
Intersection Observer is a browser API that executes a function when a certain part of the browser window, or parent element, intersects a target element. In simpler terms, the Intersection Observer API allows us to react to a specific element or elements coming into view. The most common use of this API is to trigger an action when a target element scrolls into view.
For example, here we use the IntersectionObserver API to change the src of an img tag whenever it is scrolled into view. This is what we will be recreating here.
Why was the Intersection Observer API Created?
The Intersection Observer API was created to provide a more efficient way to detect the visibility of an element. Previously, detecting the visibility of an element relied on event handlers. This caused performance problems as these event handlers run on the main thread and are fired constantly as the user is scrolling. On the other hand, the Intersection Observer API registers a callback function that gets executed when the target element enters or exits a defined area. The Intersection Observer API is also an asynchronous API meaning that the main thread no longer needs to watch for these intersections. However, the callback function is still executed on the main thread.
IntersectionObserver Target and Root
Before we begin, lets create some target elements and a root element. Target elements intersect the root element, causing an action to be fired. Here, the viewport will be the root element and the images will be the target elements.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.img {
height: 400px;
width: 600px;
}
</style>
</head>
<body>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
<img class="img" src="./assets/404.png"/>
</body>
</html>
Note that the root element must be a parent of the target elements. Here, the images are children of the viewport. Lets also capture these HTML elements inside a JavaScript array.
const images = document.getElementsByTagName('img');
IntersectionObserver Object
Now lets work with the Intersection Observer API. To do so, we first need to instantiate an IntersectionObserver object. The IntersectionObserver takes a callback function as a first argument and a configuration object as a second argument.
const myCallback = (entries, observer) => {};
const myOptions = {};
const myObserver = new IntersectionObserver(myCallback, myOptions);
The callback function receives a list of everything the observer is watching and the observer itself. Each element that the observer watches implements an interface that describes the intersection between the target element and its root element at a specific time. For example, it has the property isIntersecting.
const myCallback = (entries, observer) => {
for (const entry of entries) {
if (entry.isIntersecting) {
}
}
}
isIntersecting is a readonly boolean property that is true if the target element intersects with the root. For this demonstration, this is the img tag coming into the viewport. When this happens, we want to change the src of the image. We can access the current target element that came into view by using the target property.
const myCallback = (entries, observer) => {
for (const entry of entries) {
if (entry.isIntersecting) {
entry.target.src = './assets/pizza.jpeg';
myObserver.unobserve(entry.target);
}
}
}
The target property allows us to access the img tag itself and then change the src tag. We then tell the observer to no longer watch that img by passing it to the unobserve method of the observer. Before we go any further though, we need to specify the viewport as the root element by using the root key in the options object. If we set it to null then the observer will use the viewport as the root.
const myOptions = {
root: nulll
};
Next, we can specify the degree of intersection between the target element and its root. This is a value between 0.0 and 1.0 and is the percentage of the target element that is visible. This is passed to the threshold key in the options object.
const myOptions = {
root: null,
threshold: 1.0
};
Setting threshold to 1.0 here tells the Intersection Observer to fire the callback function when the target element is completely inside the root element. However, for any of this to work we also need to tell the observer to observe all of these image tags.
for (const image of images) {
myObserver.observe(image);
}
The observe method tells the observer what to observe. What is passed in here is what will be available in the callback function entries parameter. Now we just simply need to run the program and watch the pizza dogs appear as we scroll!