Change style on scroll using Intersection Observer API

Change style on scroll using Intersection Observer API

It is a common scenario on landing pages or any other web pages to show some animation change or style change on scrolling to a specified section of the page. I used to use scroll event listener and calculate the element offset position to achieve these results (For example, using element.getBoundingClientRect() and onScroll event listener). But, recently I found a better solution that required less code for me. That is a native web API named Intersection Observer API.

What is Intersection Observer API:

From the name of the API, we can get an idea about it. It has the word 'Observer' in it which means this API observes something in the DOM. What does it observe? It observes the intersection of elements. We can define a target element on which the observation will occur and when that target element will interset with one of our defined element (another DOM element or the viewport) then it will notify us. Based on the observer notification we can take an action.

According to MDN:

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.

How to use it:

We need two basic elements to use this API. Those are:

  1. Target element (The element on which the API will observe)
  2. Defined element (Another DOM element or the viewport with whom the target element will intersect). This is called 'root element' or 'root'.

The observer API uses a callback function that is called when the target element intersects the root element with respect to a specific threshold value.

Other than target and root element the API takes two more options to calculate the intersection. One is 'rootMargin' and another is 'threshold'.

The rootMargin is like CSS margin which is used to customize the boundingRect of the root element and the threshold is a percentage value from 0 to 1.

By declaring the threshold value we can say at which percentage of intersection with the root element we should do some task. The threshold value can be a single value or an array. Multiple threshold values will invoke a callback function on those threshold values. Let say, if we define the threshold value as [0.25, .5 ], then the observer will notify when the scroll intersection goes through 25% and 50% of the target element from the top.

Let's see how we can implement it. At first we need to create the options for the observer:

let options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}

Then we need to create a new observer with the options and a callback function. The callback function receives an IntersectionObserverEntry object array. The array will have an object for every value in the threshold array. Oh! The array has an element entry for the reference of the observer too.

let observer = new IntersectionObserver(callback, options);

Observation time! In the last step, we have to add the observer to a target element to command the API to observe that element's intersection with the root element.

let target = document.getElementById('targetElement');
observer.observe(target);

Here is an example:

In the example, we are observing a target element with green background. Here we have set root as null because when we want to observe the intersection in respect to the viewport or the closest scrollable ancestor we have to use null as root. The threshold value is used .5. So, when we will scroll to the half of the target element the observer will invoke the callback function. Here the callback function is just an alert.

Bonus: How to use in React:

As, it is a Web API, so we can easily use it in React too. Here's how we can use with the help of useRef, useEffect hooks:

const videoContainerRef = useRef(null);

useEffect(() => {
        const observer = new IntersectionObserver(
            ([entry]) => {

                if (entry.isIntersecting) {
                    console.log(entry);
                    //playing a video on scrolling to that element
                    playerRef.current.play();
                } else {
                    playerRef.current.pause();
                }
            },
            {
                root: null,
                rootMargin: "0px",
                threshold: 0.2
            }
        );
        if (videoContainerRef.current) {
            observer.observe(videoContainerRef.current);
        }
    }, [videoContainerRef]);

If you want to know more about this API in detail then MDN docs has a great resource to check: developer.mozilla.org/en-US/docs/Web/API/In..

Thanks for reading the article. This is my very first article here. So, let me know if you have any suggestions or questions about the article in the comments.

Cover Photo by WebFactory Ltd on Unsplash