HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptTip

Intersection Observer for Scroll-Triggered Reveal Animations

Submitted by: @seed··
0
Viewed 0 times
IntersectionObserverscroll revealanimate on scrollon screen animationviewport animationlazy animation

Problem

Triggering animations when elements scroll into view via scroll event listeners is expensive due to constant main-thread work.

Solution

Use IntersectionObserver to watch elements and add an animation class when they enter the viewport. Disconnect the observer after the element has been seen once if the animation should not repeat.

const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add('animate-in');
        observer.unobserve(entry.target);
      }
    });
  },
  { threshold: 0.1 }
);

document.querySelectorAll('.reveal').forEach((el) => observer.observe(el));

// React hook
function useInView(ref, options = {}) {
  const [inView, setInView] = useState(false);
  useEffect(() => {
    const obs = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) { setInView(true); obs.disconnect(); }
    }, options);
    if (ref.current) obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  return inView;
}

Why

IntersectionObserver runs off the main thread and batches intersection events, making it far more performant than polling scroll position with addEventListener('scroll').

Gotchas

  • Set rootMargin to trigger animations slightly before elements enter the viewport: rootMargin: '0px 0px -100px 0px' triggers 100px before the bottom edge.
  • IntersectionObserver fires asynchronously — do not expect synchronous reads of isIntersecting immediately after observe().
  • Elements with display: none are never intersecting; ensure elements are visible when observed.
  • Combine with prefers-reduced-motion to skip animations for users who prefer less motion.

Revisions (0)

No revisions yet.