What is it
Intersection Observer is a browser provided API/method to observe the visibility and position of a DOM element relative to the containing viewport or root element.
In simple words it keeps noting if the position of your selected DOM element is in the viewport while scrolling, when your selected DOM element touches the bottom of page while scrolling you can make a method get triggered (i.e., callback)
Where to use it, benefits
– It gives a smooth scrolling experience to the user
– Lazy-loading of images or other elements as the page is scrolled
– Very efficient in case your contents’ size are large and you want them to
downloaded one by one
– Very efficient in case of shopping website where users keep getting new products as they scroll down
– If your page content is very long and you don’t want user to have to change the page
– It gives the user and infinite-loading experience
How it looks like
Notice as we are scrolling down, new items are being appended at bottom (which you get from API call) also notice the smooth user experience.

Source Code
To understand the topic better we have already kept our Intersection Observer project at our Github location.

How the Intersection Observer works
new IntersectionObserver(callback , optionalParameter)We can pass an optionalParameter in which we tell about from how which distace from the viewport our callback method should be triggered.
var optionalParameter = { root: null, rootMargin: '400px', // higher it is more eagerly the // new DOM element gets appended threshold: 1.0 }
DEFINATION:
Root
Refers to the element that the target is intersecting against. It can be null which would mean that the root is now the viewport.
rootMargin
It provides the margin which can be positive or negative which gets added to viewport height.
For ex – If rootMargin is 200px, the callback will be called even from a distance of 200px, in other words, it means, even when there is html element with height 200px yet to be scrolled down the callback will be triggered.
Threshold
It can be between 0 & 1. 0 means as soon as you scroll the 0.001% of the target element the callback will be hit. 1 means you have to scroll the target element completely to get the callback. Default is 50%
let options = {
root: document.getElementById('#id'),
rootMargin: '400px',
threshold: 1.0
}
var callback = entries => {
// your logic
// load more items with a class name 'toObserver'
}
const observer = new IntersectionObserver(callback, options)
observer.observe(document.querySelector('.className'))
After creating the object of IntersectionObserver we call the observe method and pass html elements which all we want to observe, for example elements with class name – ‘toObserver’
Let's lazy load images in UI using Intersection Observer
As show in above video, we are loading images in our website in a lazy fashion means we will not load all the images at once, as the user will scroll down, we will be noticing the scroll movement, as soon as the scroll will reach near bottom, we will trigger our callback and via callback we’ll load more images.
Notice two things as shown in above video:
1- As soon as we a card gets into visible area of screen, we add a class called “show” to the card
2 – As soon as last card is scrolled from the html, we are adding new cards at the bottom, notice the new div elements will class name cardnew(with red border) being added in UI/DOM
Things which we can control here are –
Margin – Currently we are adding new cards as soon as our scroll position reaches near 200px from the bottom, we can increase or decrease this via rootMargin in the option.
Threshold – Means how much % of a card is to be scrolled to get the callback
Project structure
Index.html
It’s the only UI file, so we can directly run it in browser.
Script.js
Notice there are two IntersectionObserver being created.
1st is adding show class to the card, we are observing all the elements with class name card
On intersection we are adding the class show, then we unobserve the card using observer.unobserve() method.
2nd is adding appending new card at bottom using loadMoreCards() method, these new cards have cardnew class (red border). In this IntersectionObserver we are also passing the options object to control Margin/Threshold
const cards = document.querySelectorAll('.card') // First IntersectionObserver const observer = new IntersectionObserver(entries => { entries.forEach(entry => { entry.target.classList.toggle('show', entry.isIntersecting) if(entry.isIntersecting){ observer.unobserve(entry.target) } }) }) cards.forEach(card => { observer.observe(card) })
// Second IntersectionObserver let options = { root: null, rootMargin: '400px', threshold: 1.0 } const lastCardObserver = new IntersectionObserver(entries => { const lastCard = entries[0]; if(!lastCard.isIntersecting){return} loadMoreCards(); lastCardObserver.unobserve(lastCard.target) lastCardObserver.observe(document.querySelector('.card:last-child')) }, options) lastCardObserver.observe(document.querySelector('.card:last-child')) const cardcontainer = document.querySelector('.card-container'); const loadMoreCards = () => { for(i = 0; i < 3; i++){ const card = document.createElement('div') card.textContent = 'card new '; card.classList.add('card') card.classList.add('cardnew') observer.observe(card) cardcontainer.append(card) } }
Style.css
For better look n feel also add a jpg file with name a.jpg in the same folder.
.card-container{ display: flex; flex-direction: column; gap: 1em; align-items: flex-start; } .card_at_end{ background: white; border: 1px solid black; color: black; transform: translateX(50px); transition: 150ms; padding: 21px 0; height:79px; } .cardnew{ background: red !important; opacity: 0; border: 1px solid blue; transform: translateX(50px); transition: 150ms; padding: 5px; content:url('./a.jpg'); height:79px; } .card{ background: white; opacity: 0; border: 1px solid black; color: black; transform: translateX(50px); transition: 150ms; padding: 5px; content:url('./a.jpg'); height:79px; } .card.show{ transform: translateX(0); opacity: 1 !important; }
Summary
We just saw how easily we can implement lazy-loading using IntersectionObserver. You can get similar effect as when you scroll down a video on YouTube you get to see comments.
More from Node/Javascript:




