DEV Community

Cover image for Intersection observer  API

Posted on


Intersection observer API

Modern websites depend on scroll events that is the Cliché way of handling scrolling (window.scrollY). Scrolling can trigger lazy-loading of images and data and so much more. Unfortunately these scroll events are unreliable and intensive to use in my opinion and causes implementation issues which leads to poor browser performance.

The Intersection Observer API was created as a solution to solve the issues associated with "scroll events". It is browser API that provides users a way to observe given elements and monitor changes in their intersection like the name says "INTERSECTION" with a given ancestor element or the viewport (Browser window) itself.

Talking about the problem with the current implementation which is the scroll event. Consider a modern website , there are a lot of scroll events going on that we do not notice as users. The ads on the site load when scrolled into view, new contents load when the bottom of the page is reached, elements animate from time to time, and images are loaded lazily at times as the user reached them (Note: not all sites lazy load images). I myself have only done this once. These scroll events rely basically on countless loops calling performance intensive methods like the Element.getBoundingClientRect() to get the required position information.

When these methods run, its all on the main thread and as we know JavaScript is a single threaded language meaning an issue with one causes a break in the code. ** The Intersection Observer API passes off management of intersection events to the browser by using callback functions tied to the intersection status of specific elements. The browser can manage these events more effectively, optimizing for performance.**

The API is currently supported on most browsers, Chrome, Edge, Firefox and even Safari, which is pretty nice.

Lets take a look at some of the Concepts and basic usage of the observer.

Concepts & Basic Usage

To fully understand why the Intersection Observer API is so much better for performance, let’s start with a look at the basics.


A few key terms are used to define any instance of an Intersection Observer. The root is the element which waits for an object to intersect it. By default, this is the browser viewport, but any valid element may be used.

While the root element is the basis of a single IntersectionObserver, the observer can monitor many different targets. The target may also be any valid element, and the observer fires a callback function when any target intersects with the root element.

Checkout the GIF in the link below to get a bit of visual representation.

Basic Usage

Setting up a simple IntersectionObserver is straightforward. First, call the IntersectionObserver constructor. Pass a callback function and desired options to the constructor function:

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

As seen above, a few options are available to set in the constructor:


The root is the element which is used to check for intersections of the target element. This option accepts any valid element, though it’s important that the root element be an ancestor of the target element for this to work. If a root isn’t specified (or null is the provided value), the browser viewport becomes the root.


The rootMargin value is used to grow or shrink the size of the root element. Values are passed in a string, with a CSS-like format. A single value can be provided, or a string of multiple values to define specific sides (e.g. '10px 11% -10px 25px).


Last, the threshold option specifies the minimum amount the target element must be intersecting the root for the callback function to fire. Values are floating point from 0.0 - 1.0, so a 75% intersection ratio would be 0.75. If you wish to fire the callback at multiple points, the option also accepts an array of values, e.g. ~[0.33, 0.66, 1.0]~.

Once the IntersectionObserver instance is created, all that’s left is to provide one or more target elements for observation:

const target = document.querySelector('#target');
Enter fullscreen mode Exit fullscreen mode

From here, the callback function will fire anytime the target(s) meet the threshold for intersection

const callback = function(entries, observer) {
    entries.forEach((entry) => {
        // do stuff here
Enter fullscreen mode Exit fullscreen mode

Calculation Intersections

It’s important to understand how intersections are calculated. First, the Intersection Observer API considers everything to be a rectangle for the sake of this calculation. These rectangles are calculated to be the smallest they can possibly be, while still containing all target content.

Check the GIF below to get a visual representation

Beyond the bounding boxes, consider any adjustments to the bounding box of the root element based on rootMargin values. These can pad or decrease the root size.

Check out the GIF below to get a visual representation of the bove


Finally, it’s crucial to understand that unlike traditional scroll events, Intersection Observer isn’t polling constantly for every single change in intersection. Instead, the callback is only called when the provided threshold is reached (approximately). If multiple checks are required, simply provide multiple thresholds.

You want to learn more, check out this series by Kevin Powell i used in getting an understanding of the intersection observer API
Kevin Powell: Link

Top comments (0)