Animate on Scroll in JavaScript using the Intersection Observer API

Animating elements while scrolling the page is still a very popular feature in web design. However, those animations depend on external plugins or libraries that add a lot of unnecessary code to our projects and end up making our pages heavier. We will be using the Intercept Observer API which is already supported by all modern web browsers to create the same animation when users scroll down the page. This is the final demo and can be seen on JSBin.

The Intersection Observer API

The purpose of this API is to track the position and visibility of elements in the browser. It has good support across modern web browsers and there is a polyfill for browsers that don’t support it.

Usage

In modern web design and development, the Intercept Observer can be very useful. Real world examples are:

  • Loading more data with Ajax when the user reaches the bottom of the page (Infinite Scrolling).
  • Lady loading images in order to improve the performance of the page.
  • Animating only the elements that are visible to the users.

Animate on Scroll

The HTML for this example is a list of div elements with the “item” class as follow:

<div class="item">
   <h2></h2>
   <p></p>
</div>

The CSS basically contains three main classes. The “item” class which provides the default style of the elements. The other two classes are “animation” and  “animated” which are used for the animation when the item is on the screen for the first time.

The reason for using the “animation” class and not move its content to the “item” class is that the opacity should only work if the Intercept Observer object is supported and you don’t want to make the opacity:0 by default on the items since you should not depend purely on JavaScript in making the elements visible.

.item {
  min-height:200px;
  width:50%;
  padding:1rem;
}

.animation {
  opacity:0;
  transition:opacity 1s, transform 1.3s;
}
.animated {
  opacity:1;
  transform:translateY(-2rem);
}

JavaScript

In the JavaScript file, first, we check if the Intersection​Observer is supported. If the browser does not support it, it will just ignore the code and continue with the page.

Then, we create a callback function that will be passed to the Intersection​Observer as the first parameter. The callback function receives an array of IntersectionObserverEntry objects. The object has several useful properties. However, the one that we are interested with is the target attribute which is the actual HTML element that is entering the screen (the viewport for our case). With the array of entries, we check if the object is intersecting the viewport (In the near future, we will be able to use the isVisible attribute). If the element is intercepting, and it does not have the class “animated”, then add the class to perform the animation.

The next part is to create the actual observer and passing the callback function. In addition to the callback function, the options parameter is passed to the object creation. The options needed for this example are root which is set to null since we want the viewport, and threshold set to 0.3 that is executed when the item is 30% visible on the viewport.

The last snippet is telling the observer object to “observe” the elements with the class “item” while adding the class “animation” on those items in order to add the transition when they become visible.

//Only Use the IntersectionObserver if it is supported
if (IntersectionObserver) {
    //When the element is visible on the viewport, 
    //add the animated class so it creates the animation.
    let callback = function(entries) {
        entries.forEach(entry => {
            //if the element is visible, add the animated class
            if (entry.isIntersecting &&
                !entry.target.classList.contains('animated')) {
                entry.target.classList.add('animated');
            }
        });
    }
    //Create the observer
    let observer = new IntersectionObserver(callback, {
        root: null,
        threshold: 0.3
    });

    //Get and observe all the items with the item class
    let items = document.querySelectorAll('.item');
    items.forEach((item) => {
        item.classList.add('animation');
        observer.observe(item);
    });
}

Final Demo

Conclusion

This is just a short example of what can be done the Intersection Observer. However, you could extend the example to use Ajax and load more content asynchronously, changing the animation, making different animations for each paragraph, etc. Finally, as it is supported by the browser, we don’t have to worry about long term support of a external library. Thus, we are sure that the code will work long term.

Teylor Feliz
Teylor Feliz

Teylor is a seasoned generalist that enjoys learning new things. He has over 20 years of experience wearing different hats that include software engineer, UX designer, full-stack developer, web designer, data analyst, database administrator, and others. He is the founder of Haketi, a small firm that provides services in design, development, and consulting.

Over the last ten years, he has taught hundreds of students at an undergraduate and graduate levels. He loves teaching and mentoring new designers and developers to navigate the rapid changing field of UX design and engineering.

Articles: 182