2HAASStart a project
All posts

Code Snippets

Intersection Observer: react when elements scroll into view

Scroll listeners that measure element positions are slow and fiddly. Intersection Observer tells you when an element enters the viewport, with a few lines of code.

The 2HAAS team2 min read

Knowing when an element becomes visible used to mean listening to the scroll event and calling getBoundingClientRect() on every element, many times a second. That work runs on the main thread, forces layout and makes scrolling feel heavy.

The Intersection Observer API turns it around. You tell the browser which elements you care about, and it calls you when their visibility changes.

The basic pattern

const observer = new IntersectionObserver(
  (entries) => {
    for (const entry of entries) {
      if (!entry.isIntersecting) continue;
      entry.target.classList.add("is-visible");
      observer.unobserve(entry.target); // one time only
    }
  },
  { rootMargin: "0px 0px -10% 0px", threshold: 0.1 },
);

document.querySelectorAll("[data-reveal]").forEach((el) => observer.observe(el));

Each element gets the is-visible class the first time it scrolls into view, and is then dropped from the watch list. This site uses the same pattern for its scroll reveals.

The options

Option Meaning Example
root The scrolling container to watch. Defaults to the viewport. A scrollable panel
rootMargin Grows or shrinks the area that counts as visible "400px" to trigger early
threshold How much of the element must be visible 0.1 for 10 percent, 1 for all of it

Useful things to build with it

Infinite scroll. Watch one empty element at the end of the list and load the next page as it approaches.

const sentinel = document.querySelector("#load-more");

new IntersectionObserver(
  async ([entry]) => {
    if (entry.isIntersecting) await loadNextPage();
  },
  { rootMargin: "400px" },
).observe(sentinel);

Lazy loaded components. Load a map, a comment section or a video player only when the user gets near it.

Pausing work off screen. Stop a video or an animation that nobody can see, and resume it when it returns.

Impression tracking. Record that a banner was seen, with a threshold that matches your definition of seen.

Sticky header states. Observe a small element at the top of the page to know when the user has scrolled past it.

Use the simpler tool for images

For plain images you do not need JavaScript at all. The loading="lazy" attribute does the job in every modern browser. See native image lazy loading. Keep Intersection Observer for cases where code has to run.

Things to know

  • The callback fires once right after observe(), with the element's current state. Check isIntersecting and do not assume it.
  • Call unobserve() or disconnect() when you are done, especially in single page apps where components come and go.
  • It reports changes asynchronously. Do not use it for animation that has to track the scroll position exactly.
  • If you use it for reveal animations, respect prefers-reduced-motion and show the content without animating.

The takeaway

Intersection Observer replaces a whole class of scroll handlers with a few lines that the browser runs efficiently. If your code listens to scroll to find out what is visible, this is the replacement.

Keep reading

  1. Code Snippets2 min read

    Web Workers: move heavy work off the main thread

    Heavy JavaScript freezes the page because it shares a thread with the interface. A Web Worker runs that work in the background. A working example and the limits to know.

  2. Guides2 min read

    How to reduce JavaScript bundle size

    Every kilobyte of JavaScript is downloaded, parsed and run before a page responds. Measure the bundle, split it by route, lazy load the rest and trim dependencies.

  3. Tech Tips2 min read

    JavaScript performance: keep the main thread free

    A page can load fast and still feel slow. Batch DOM updates, debounce noisy events and break up long tasks to keep the interface responsive.

Tell us what’s in the way.

A few lines is enough. You get a candid yes, a candid no, or a sharper question.

  • Working software in week four
  • A reply in one business day
  • Handover is the deliverable

Prefer email? [email protected]

The problem, who it is for, and what is in the way right now.

One business day to a real reply. No sales sequence, no call required.