Build Your Own Version of the Intersection Observer Polyfill: A Step-by-Step Guide

Build Your Own Version of the Intersection Observer Polyfill: A Step-by-Step Guide

Understanding the inner workings of web APIs can be both enlightening and empowering. In this guide, we will dive into how you can build your own version of this API from scratch.

What is the Intersection Observer?

Before we roll up our sleeves and start coding, let’s first understand what the Intersection Observer API does. It allows developers to efficiently trigger function calls based the visibility of elements on a web page without resorting to costly operations that can impact performance.

Why Build Your Own?

While the browser’s native Intersection Observer API is optimized for performance, building your own version can give you a deeper understanding of how web APIs work and offer greater control for customized use cases.

intersection observer polyfill

As illustrated above, the API works by monitoring the intersection between the target element and its parent container.

  1. Container Element: The properties of this element indicate it’s the parent container. It has a clientHeight (visible area of an element content, including padding but not the scrollbar, border, or margin) and a scrollHeight (entire height of the content, including what is not visible on the screen). An initial scrollTop of 0 indicates the scroll position starts at the top of the container.
  2. Observable Element Container: This box represents a container that holds an element to be observed. Its height is greater than its parent container, meaning it has an overflow (content that doesn’t fit within the dimensions of the parent container).
  3. Observable Element: This is the child element within the container that will be observed. It has an offsetTop (distance of the current element relative to the top of the offsetParent node) and a clientHeight. It seems to be the element that we want to check visibility for within the scrollable container.

The Basics of Visibility Detection

To detect the visibility of an element, we need to consider its position within the container and compare it to the viewport’s scroll position.

intersection observer polyfill

observable.offsetTop < container.clientHeight + scrollTop means the top of the element is visible.

intersection observer polyfill


observable.offsetTop + observable.clientHeight > scrollTop indicates the bottom of the element is visible.

intersection observer polyfill

The final condition combines above two to confirm that the entire element is visible within the viewport.

In the images, the mechanics of how an element becomes visible within a scrolling viewport, using variables like offsetTop, scrollTop, clientHeight, and scrollHeight.

  1. Determine the position of the observable element with elementOffsetTop.
  2. Compare the observable element's position with the root element's scroll position rootScrollTop and visible area rootClientHeight.
  3. Use these comparisons to decide whether the observable element is visible (isVisible).
  4. Call the callback function with the visibility status of the observable element.

This logic is typical for implementing “lazy loading” of content or for analytics to determine if a user has seen an element, which is common in web development to enhance performance and user experience. It is based on the Intersection Observer API principles, which 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.

Setting Up the HTML Structure

Firstly, we need a basic HTML structure with a container and an element that we will observe.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./index.js" defer></script>
    <link rel="stylesheet" href="./index.css">
</head>
<body>
    <div id="root">
        <div id="container">
            <div id="observable">
                
            </div>
        </div>
    </div>
</body>
</html>        

Styling the Elements

Next, we style our elements to ensure that we have a scrollable container and a clearly defined observable element.

*{
    margin:0;
    padding:0;
    box-sizing: border-box;
}

html, body{
    height: 100%;
}

#root{
    height:100%;
    overflow-y: scroll;
    overflow-x: auto;
}

#container{
    position:relative;
    width: 80%;
    height: 6000px;
    background-color: rgb(142, 142, 142);
    margin:auto;
}

#observable{
    position:absolute;
    top:50%;
    left:50%;
    transform:translateX(-50%);
    height:300px;
    width:300px;
    background-color: rgb(163, 204, 240);
}        

Writing the JavaScript Logic

The core of our custom Intersection Observer is the JavaScript that powers the visibility logic.

const root = document.getElementById('root');
const container = document.getElementById('container');
const observable = document.getElementById('observable');

console.log(root, container, observable);

class IntersectionObserver{
    constructor(root){
        this.root = root;
        this.observables = new Map();
        this.init();
        this.visibleElements = new Set();
    }

    scroll=(e)=>{
        const rootScrollTop = this.root.scrollTop;
        const rootClientHeight = this.root.clientHeight;
        this.observables.forEach((callback, element)=>{
            const elementOffsetTop = element.offsetTop;
            const elementClientHeight = element.clientHeight;
            const isVisible = rootScrollTop <= elementOffsetTop + elementClientHeight
                && elementOffsetTop <=rootClientHeight + rootScrollTop;
            if(isVisible){
                if(!this.visibleElements.has(element)){
                    callback('true', element);
                    this.visibleElements.add(element);
                }
            }
            else{
                if(this.visibleElements.has(element)){
                    this.visibleElements.delete(element);
                    callback('false', element);
                }
            }
        })
    }

    init(){
        this.root.addEventListener('scroll', this.scroll);
    }

    addObservable(el, cb){
        this.observables.set(el, cb);
    }

    removeObservable(el){
        this.observables.delete(el);
    }

    decompose(){
        this.root.removeObservable('scroll', this.scroll);
    }
};

const intersectionObserver = new IntersectionObserver(root);
intersectionObserver.addObservable(observable, (status, element)=>{
    console.log(status, element);
});        

Testing Your Intersection Observer

Now, it’s time to test your custom Intersection Observer in action. Scroll the container and watch the console logs to see the visibility changes.

Discover the full code on my GitHub repository at Intersection-observer-polyfill. If you appreciate the work, consider starring the repo! Contributions are welcome, so feel free to fork it and submit a pull request if you have enhancements you’d like to add.

Conclusion

By following this guide, you have created a functional Intersection Observer from scratch. Experiment with it, tweak it, and use it to understand the fundamentals of asynchronous UI monitoring.

If you’ve found this step-by-step guide helpful, please send some applause my way with a ?? or two — or as many as you think this article deserves! Your support motivates me to share more insights and guides.

Don’t forget to follow me on Medium for more content like this. Let’s stay connected and continue the conversation on LinkedIn and explore code together on GitHub. I’m looking forward to engaging with all of you and growing our community of passionate developers.

Until next time, keep coding and stay curious!


[This post originally appeared on https://medium.com/@kamresh485/building-your-own-version-of-the-intersection-observer-a-step-by-step-guide-c58309627f88. Please give it a LIKE.]

Utkarsh Kumar Raut

Poet on terminals compiling dreams.

9 个月

Nice. We use Intersection observer at OrangeBooks Publication landing pages where pop-up is shown when footer is reached. https://www.orangebooks.in/

要查看或添加评论,请登录

社区洞察

其他会员也浏览了