← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

IntersectionObserver API

javascript HTML5 Intermediate
debt(d7/e3/b3/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate no automated detection ('automated: no') and only loose code patterns (getBoundingClientRect|scroll.*img). Missing unobserve() calls, threshold misconfiguration, and missing rootMargin are runtime/behavioral issues that won't be caught by linters or type checkers — they require manual testing or code review to surface.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes a straightforward pattern replacement: swap scroll event + getBoundingClientRect for IntersectionObserver, add rootMargin configuration, and ensure unobserve() calls. This is contained within a single component (lazy-loading or scroll handler) and doesn't require cross-file refactoring.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). IntersectionObserver is scoped to web contexts and typically isolated to specific performance-critical components (lazy loading, infinite scroll, visibility tracking). It doesn't impose a persistent tax across the codebase; once a component uses it correctly, the choice is localized. It doesn't reshape the overall system architecture.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field explicitly states a major gotcha: developers expect IntersectionObserver to fire synchronously during scroll (like scroll events), but it actually fires asynchronously between frames, batching intersections. This contradicts familiar scroll-event behavior. Additionally, common_mistakes reveal threshold:0 vs threshold:1 confusion and the subtle need for rootMargin preloading—both non-obvious behaviors that trip developers.

About DEBT scoring →

TL;DR

IntersectionObserver fires when an element enters or leaves the viewport — the modern way to implement lazy loading, infinite scroll, and scroll-triggered animations.

Explanation

IntersectionObserver(callback, options) observes elements for viewport intersection. Options: root (default viewport), rootMargin (expand/shrink root), threshold (0–1, fraction visible to trigger). The callback receives IntersectionObserverEntry[] with isIntersecting, intersectionRatio, boundingClientRect. Use cases: lazy load images (observe img, set src when visible), infinite scroll, animate elements on scroll, sticky header detection. Unobserve after first intersection for one-shot triggers. Far more performant than scroll event + getBoundingClientRect polling.

Common Misconception

IntersectionObserver fires synchronously during scroll — it fires asynchronously between frames, batching all intersections in one callback.

Why It Matters

Replacing scroll event listeners with IntersectionObserver eliminates layout thrashing and dramatically improves scroll performance.

Common Mistakes

  • Not calling unobserve() after one-shot events like lazy loading.
  • Using threshold:0 for 'element is fully visible' — that's threshold:1.
  • Not setting rootMargin to preload images slightly before they're visible.

Code Examples

✗ Vulnerable
window.addEventListener('scroll', () => {
    images.forEach(img => {
        const rect = img.getBoundingClientRect();
        if (rect.top < window.innerHeight) img.src = img.dataset.src;
    });
});
✓ Fixed
const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            entry.target.src = entry.target.dataset.src;
            obs.unobserve(entry.target); // One-shot
        }
    });
}, { rootMargin: '200px' }); // Preload 200px before visible

document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));

Added 23 Mar 2026
Edited 5 Apr 2026
Views 20
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Amazonbot 6 Unknown AI 3 Perplexity 3 Google 2 ChatGPT 1 Majestic 1 Ahrefs 1
crawler 16 pre-tracking 1
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Low
⚡ Quick Fix
Replace scroll event + getBoundingClientRect with IntersectionObserver. Use rootMargin for preloading. Always unobserve() after one-shot triggers.
📦 Applies To
javascript HTML5 web
🔗 Prerequisites
🔍 Detection Hints
getBoundingClientRect|scroll.*img
Auto-detectable: ✗ No
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function

✓ schema.org compliant