Building A Dynamic Header With Intersection Observer

Have you ever needed to build a UI where some component on the page needs to respond to elements as they’re scrolled to a certain threshold within the viewport — or perhaps in and out of the viewport itself?

In JavaScript, attaching an event listener to constantly fire a callback on scroll can be performance-intensive, and if used unwisely, can make for a sluggish user experience. But there is a better way with Intersection Observer.

Intersection Observer API

The Intersection Observer API is a JavaScript API that enables us to observe an element and detect when it passes a specified point in a scrolling container — often (but not always) the viewport — triggering a callback function.

Intersection Observer can be considered more performant than listening for scroll events on the main thread, as it is asynchronous, and the callback will only fire when the element we’re observing meets the specified threshold, instead every time the scroll position is updated. In this article, we’ll walk through an example of how we can use Intersection Observer to build a fixed header component that changes when it intersects with different sections of the webpage.

Historically, detecting visibility of an element, or the relative visibility of two elements in relation to each other, has been a difficult task for which solutions have been unreliable and prone to causing the browser and the sites the user is accessing to become sluggish. As the web has matured, the need for this kind of information has grown. Intersection information is needed for many reasons, such as:

  • Lazy-loading of images or other content as a page is scrolled.
  • Implementing “infinite scrolling” web sites, where more and more content is loaded and rendered as you scroll, so that the user doesn’t have to flip through pages.
  • Reporting of visibility of advertisements in order to calculate ad revenues.
  • Deciding whether or not to perform tasks or animation processes based on whether or not the user will see the result.

Basic Usage

const options = {
root: document.querySelector(‘[data-scroll-root]’),
rootMargin: ‘0px’,
threshold: 1.0

const callback = (entries, observer) => {
entries.forEach((entry) => console.log(entry))

const observer = new IntersectionObserver(callback, options)