The JavaScript Intersection Observer

Pieces 🌟 - Feb 9 '23 - - Dev Community

The file structure in an IntelliJ IDE.

Introduction

In this tutorial, we’ll discuss the JavaScript Intersection Observer and understand how to use it for noting and creating changes in JavaScript applications. We’ll also explore its concepts, and try out a demo to accelerate the learning process.

What is the JavaScript Intersection Observer?

The JavaScript Intersection Observer is an application programming interface (API) that provides a method to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport (the part of the document visible to the user on their window or screen).

The Intersection Observer API allows your code to register a callback function that is executed whenever an element you wish to monitor enters or exits another element (or the viewport), or when the amount by which the two intersections change at a requested amount. In this manner, sites no longer need to do anything on the main thread to observe this kind of element intersection, and the browser becomes free to appropriately optimize intersection management.

When to Use the Intersection Observer

The Intersection Observer API allows you to configure a callback initiated when either of these events occur:

  • A target element intersects a specified element or the device's viewport. That specified element is called the root element or root for the Intersection Observer API’s purposes.
  • The initial time an observer is initially asked to watch a target element.

It’s important to watch for intersection changes with regard to the target element's closest scrollable ancestor, or if the target element is not related to the scrollable element, the device's viewport. To watch for intersection relative to the device's viewport, state null for the root option. Whether you're using the viewport or some other element as the root, the API works the same way. It executes a callback function that you will offer whenever the visibility of the target element changes so that it crosses desired amounts of intersection with the root. The degree of intersection between the target element and its root is called the intersection ratio. This is a representation of the percentage of the visible target element, shown as a value between 0.0 and 1.0.

Why Choose the JavaScript Intersection Observer?

As the internet advances, we need to implement changes that conform with the web’s rapid evolution, hence the need for intersection information. The Intersection Observer is used for the following:

  • Lazy-loading of images or other content as a page is scrolled, and in the implementation of "infinite scrolling" on web sites, where more and more content is loaded as users scroll (so they don’t have to keep flipping through pages).
  • Observing and reporting the visibility of marketing content, campaigns, advertisements in order to calculate viewership.
  • Deciding whether or not to initiate tasks or animation processes based on if the user will see the results.
  • Scroll-spying for contextual content (navigation bars, table of contents, sections, etc.).

The Intersection Observer vs Other Observer APIs

In addition to the Javascript Intersection Observer, there are two other observer APIs: The Resize Observer and the Mutation Observer.

Resize Observer

This API consists of the Resize Observer interface, an instance that has 3 methods: the base observe(), disconnect() and the unObserve(). This interface reports changes to the dimensions of an element’s border box, or the bounding box of an SVG Element. It also provides a performance mechanism by which code can monitor an element for changes to its size specifically, with notifications being delivered to the observer each time the size changes.

Mutation Observer

The Mutation Observer interface provides the ability to watch for changes being made to the Document Object Model (DOM) tree that connects web pages to scripts or programming languages. It is designed as a replacement for the older mutation event features, which was one of the specifications of the DOM3 Events. You can use it to track changes introduced by other parts of your code and to integrate with third-party scripts.

How to Create an Intersection Observer in Javascript

You can create an intersection observer by calling its constructor and passing into it a callback function to be run whenever a threshold is crossed in one direction or another:

let options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}
let observer = new IntersectionObserver(callback, options);
Enter fullscreen mode Exit fullscreen mode

From the above, a threshold of 1.0 entails that when 100% of the target is visible within the element specified by the root option, the callback is invoked.

Intersection Observer Options

The options object passed into the intersectionObserver() constructor allows you control the circumstances under which the observer's callback is invoked. It involves the following important fields:

root

The root is the element used as the viewport for checking visibility of the target, and must be the origin of the target. This is rarely used, however. It is only useful when there is a scrolling container inside your page that you want to check observations for, since you can make the scrolling container the root element instead of the screen.

rootMargin

This is the margin around the root. It could have values similar to the CSS margin property, e.g. "20px 30px 40px" (top, right, bottom), or they can carry percentage values. This set of values either allows growth or shrinks each side of the root element's bounding box before carrying out intersections.

const observer = new IntersectionObserver(
  changeColor,
  { rootMargin: "50px" }
)
observer.observe(document.getElementById("test"))
Enter fullscreen mode Exit fullscreen mode

Threshold

The threshold can be a single number or an array of numbers that indicate the target’s percentage of visibility at which the observer's callback should be executed. To detect when visibility passes the 50% mark, you can use a value of 0.5. If you want to ensure that the callback runs every time visibility passes another 25%, the array should be specified as [0, 0.25, 0.5, 0.75, 1]. The default is always 0, which means that as soon as even one pixel is visible, the callback will run. A value of 1.0 means that the threshold is not passed until every pixel is visible.

const observer = new IntersectionObserver(
  changeColor,
  { threshold: 1 }
)
observer.observe(document.getElementById("test"))
Enter fullscreen mode Exit fullscreen mode

Calculating the Intersection Observer

The Intersection Observer API considers rectangles. Therefore, if the visible portion of an element is not rectangular, the element's intersection rectangle will be the smallest rectangle that contains all the visible portions of the element.

How to Target an Element to be Observed

After creating the observer, a target element to watch should be given:

let target = document.querySelector('#listItem');
observer.observe(target);
// the callback you setup for the observer will be executed now for the first time.
// it will wait until you assign a target to our observer (even if the target is currently not visible)
Enter fullscreen mode Exit fullscreen mode

Whenever the target meets a threshold specified for the Intersection Observer, the callback is invoked:

let callback = (entries, observer) => {
  entries.forEach((entry) => {
 // Each entry describes an intersection change for one observed
 // target element:
 //   entry.boundingClientRect
 //   entry.intersectionRatio
 //   entry.intersectionRect
 //   entry.isIntersecting
 //   entry.rootBounds
 //   entry.target
 //   entry.time
  });
};
Enter fullscreen mode Exit fullscreen mode

The above code includes a list of entries received by the callback; it includes one entry for each target that reported a change in the intersection status. Cross-check the value of the isIntersecting property to observe if the entry represents an element that is currently intersecting with the root. Keep in mind that your callback is executed on the main thread. This means that it should operate as quickly as possible. If it is going to be time-consuming, use Window.requestIdleCallback(). Also, remember that if you specified the root option, the target must always be a descendant of the root element.

Conclusion

As far as user interaction, regardless of the method you’re using and the problem you might want to solve, the Javascript Intersection Observer may be the best method to use. It provides simplicity and clarity, and it implements the conventional method of observing changes in the intersection of a target element.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .