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.
As illustrated above, the API works by monitoring the intersection between the target element and its parent 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.
observable.offsetTop < container.clientHeight + scrollTop means the top of the element is visible.
observable.offsetTop + observable.clientHeight > scrollTop indicates the bottom of the element is visible.
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.
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.]
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/