The Intersection Observer API provides a modern way to observe the intersection between one element with its ancestor element asynchronously.

Historically, detecting the visibility of an element, or relative visibility between 2 element has been a difficult task and unreliable. But why it’s so important? Because it is the requisite for many behaviors in the modern web such as:

  • Lazy load contents or images.
  • Infinite scroll
  • Reporting about how many time the content is actually viewed by users

Implementing the intersection in the past depends on an API getBoundingClientRect. That can give needed information about every element affected. But that way will impact the site’s performance. Since this code is the synchronous API, it runs on the ui thread and slow down the whole site, has negative effect to the user experience.

Consider in lazy load image example. When a page contains a large number of images, then the web’s author decides to apply lazy load for these image. Each image detects whether it’s on viewport or not by itself. The number of time Element.getBoundingClientRect() is executed is equal with the number of images belong to the web page. All of that codes run in the main thread. As a result we get a poor performance. A large number of callingElement.getBoundingClientRect() will slowdown the entire page whenever the user scrolls.

When the Web becomes more mature, we need to find a better way to deal with it and that is the reason Intersection Observer API was born. It have the same responsibility with getBoundingClientRect, but the main difference is while getBoundingClientRect is synchronous, IntersectionObserverAPI is asynchronous bases on callback concept.

Intersection observer concepts and usage

Intersection observer allow us to create a callback, which is triggered whenever an element (defined by target) intersect with either other elements or the viewport (defined by root element or root).


Using Intersection observer contain 2 phrases:

Phrase 1: Defined Intersection observer (target element doesn’t involve in this phrase, only for root element)

var options = {
    root: document.querySelector("#scrollElement") //The element that is used as the viewport for checking visiblity of the target
    rootMargin: '0px', //This value serve to grow or shrink the root element's bounding box before intersection computing
    threshold: [] //Indicate at what percentage of the target's visibility the observer's callback should be executed
var callback = function(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.time
var observer = new IntersectionObserver(callback, options);

Phrase 2: Attach the target element to observer

var target = document.querySelector('#listItem');


See the Pen Intersection Observer by hieu (@phuchieuct93abc) on CodePen.


In short, Intersection Observer API is much more elegant and effective way to detect the intersection between elements. It gains the performance boost compared to the old and slow one Element.getBoundingClientRect().

R.I.P Element.getBoundingClientRect. Welcome the Intersection Observer API era

Leave a Reply