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

Intersection Observer API

Frontend ES2015 Intermediate
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list Lighthouse and ESLint, and the code_pattern indicates ESLint can flag scroll event listeners used for visibility detection. This is not a compiler/syntax error (d1) nor caught by a default linter rule out of the box (d3), but a specialist performance audit tool like Lighthouse or a configured ESLint rule can surface it.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes replacing scroll event listeners with IntersectionObserver — a targeted refactor within the component(s) using scroll-based visibility. It is more than a one-line patch (e1) because the callback logic and observer setup must be restructured, but it is contained within one component at a time rather than spanning multiple files.

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

Closest to 'localised tax' (b3). The applies_to scope is web contexts generally, and the tags are frontend/javascript/performance. Misuse (scroll listeners for visibility) imposes a performance tax on the affected feature/component but doesn't structurally poison the broader codebase — other components are unaffected unless they also use scroll-based detection.

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

Closest to 'serious trap' (t7). The misconception field states developers believe scroll event listeners are fine for visibility detection, which contradicts the actual behavior (hundreds of synchronous main-thread firings vs. asynchronous off-main-thread callbacks). A competent developer familiar with DOM events would naturally reach for scroll listeners, making this a serious behavioral mismatch. The common_mistakes also reveal multiple subtle configuration traps (threshold, rootMargin, not disconnecting) that compound the cognitive load.

About DEBT scoring →

Also Known As

IntersectionObserver lazy loading scroll detection

TL;DR

A browser API that efficiently detects when elements enter or leave the viewport — replacing scroll event listeners for lazy loading, infinite scroll, and animation triggers.

Explanation

The Intersection Observer API calls a callback when a target element intersects with a root element (or the viewport). It is asynchronous and off the main thread — far more efficient than scroll event listeners which fire on every pixel of scroll. Use cases: lazy loading images, infinite scroll, triggering CSS animations when elements enter view, sticky header detection, and ad impression tracking. threshold (0.0-1.0) defines how much of the element must be visible to trigger, rootMargin pre-loads before the element is fully visible.

Common Misconception

Scroll event listeners are fine for detecting element visibility — scroll events fire hundreds of times per second on the main thread; Intersection Observer is asynchronous and does not block rendering.

Why It Matters

Scroll event listeners for visibility detection cause main thread jank — Intersection Observer is the standard, performant replacement that does not affect scroll performance.

Common Mistakes

  • Not disconnecting the observer after the element is loaded — the observer keeps running unnecessarily.
  • threshold: 1.0 for lazy loading — waits until the element is fully visible; use 0.1 to preload before it appears.
  • No rootMargin for lazy loading — images load exactly as they enter the viewport; add '200px' margin to preload ahead.
  • Using Intersection Observer for precise scroll position — it only fires at intersection thresholds, not on every pixel.

Code Examples

✗ Vulnerable
// Scroll event — main thread, fires hundreds of times per second:
window.addEventListener('scroll', () => {
    document.querySelectorAll('img[data-src]').forEach(img => {
        const rect = img.getBoundingClientRect();
        if (rect.top < window.innerHeight) {
            img.src = img.dataset.src; // Expensive DOM query on every scroll event
        }
    });
});
✓ Fixed
// Intersection Observer — async, efficient:
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            observer.unobserve(img); // Stop observing once loaded
        }
    });
}, { rootMargin: '200px', threshold: 0.1 }); // Preload 200px before visible

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

Added 15 Mar 2026
Edited 22 Mar 2026
Views 65
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 3 pings T 2 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 15 Google 8 Scrapy 6 Perplexity 5 Ahrefs 4 ChatGPT 4 SEMrush 3 Claude 2 Bing 2 Majestic 1 Meta AI 1 PetalBot 1
crawler 47 crawler_json 4 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Replace scroll event listeners with IntersectionObserver for lazy loading, infinite scroll, and animation triggers — it runs off the main thread with zero scroll performance impact
📦 Applies To
javascript ES2015 web
🔗 Prerequisites
🔍 Detection Hints
window.addEventListener('scroll') for lazy loading or visibility detection — should use IntersectionObserver
Auto-detectable: ✓ Yes lighthouse eslint
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Low Context: File


✓ schema.org compliant