The Observation API is a collection of powerful web platform APIs that allow developers to monitor changes in the DOM, element visibility, and intersection states efficiently. It provides a modern, performance-optimized way to observe various aspects of web page elements without continuous polling.
95%Browser Support
10xPerformance Boost
3Core APIs
👁️ Intersection Observer API
The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or viewport.
Basic Implementation
// Create an intersection observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Element is visible!');
entry.target.classList.add('visible');
}
});
});
// Start observing elements
const elements = document.querySelectorAll('.observe-me');
elements.forEach(el => observer.observe(el));
🎬 Live Demo - Intersection Observer
Scroll down to see elements animate into view:
I'll animate when visible! 📈
Me too! 🎉
And me! ✨
Advanced Configuration
const options = {
root: null, // Use viewport as root
rootMargin: '0px 0px -100px 0px', // Trigger before element enters
threshold: [0, 0.25, 0.5, 0.75, 1] // Multiple thresholds
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const percentage = Math.round(entry.intersectionRatio * 100);
console.log(`Element is ${percentage}% visible`);
});
}, options);
Common Use Cases
Lazy Loading Images - Load images only when they enter the viewport
Infinite Scrolling - Load more content as user scrolls
Animation Triggers - Animate elements when they become visible
Analytics Tracking - Track element visibility for analytics
Ad Viewability - Measure ad impression visibility
🖼️ Lazy Loading Demo
Lazy loaded content will appear here...
Another lazy loaded element...
🔄 Mutation Observer API
The Mutation Observer API provides the ability to watch for changes being made to the DOM tree, including child nodes, attributes, and text content.
Basic Implementation
// Create a mutation observer
const mutationObserver = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
switch(mutation.type) {
case 'childList':
console.log('Child nodes added/removed');
break;
case 'attributes':
console.log(`Attribute ${mutation.attributeName} changed`);
break;
case 'characterData':
console.log('Text content changed');
break;
}
});
});
// Configure what to observe
const config = {
childList: true,
attributes: true,
characterData: true,
subtree: true
};
// Start observing
mutationObserver.observe(document.body, config);
🎭 Mutation Observer Demo
Click the button to see mutations in action!
Mutation Log:
Practical Applications
// Watch for dynamic content changes
const contentObserver = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
// Initialize new components
initializeNewElements(node);
}
});
}
});
});
contentObserver.observe(document.body, {
childList: true,
subtree: true
});
📏 Resize Observer API
The Resize Observer API provides a performant mechanism for observing changes to Element's size, perfect for responsive components and layouts.
Basic Usage
const resizeObserver = new ResizeObserver((entries) => {
entries.forEach(entry => {
const { width, height } = entry.contentRect;
console.log(`Element resized: ${width}x${height}`);
// Responsive behavior based on size
if (width < 768) {
entry.target.classList.add('mobile-layout');
} else {
entry.target.classList.remove('mobile-layout');
}
});
});
// Observe an element
resizeObserver.observe(document.querySelector('.responsive-component'));
📐 Resize Observer Demo
Drag the corner to resize the box below:
Resize me! Current size: Loading...
⚡ Performance Benefits
Observer APIs provide significant performance improvements over traditional polling methods.
Aspect
Traditional Polling
Observer APIs
CPU Usage
High - Continuous polling
Low - Event-driven
Battery Life
Reduced - Constant processing
Preserved - Idle when no changes
Accuracy
Limited by polling interval
Real-time change detection
Memory Usage
Higher - Multiple timers
Lower - Single observer instance
// ❌ Traditional Polling Approach (Inefficient)
setInterval(() => {
const rect = element.getBoundingClientRect();
const isVisible = rect.top >= 0 && rect.bottom <= window.innerHeight;
if (isVisible) {
// Handle visibility
}
}, 100); // Runs every 100ms regardless of changes
// ✅ Observer API Approach (Efficient)
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Handle visibility only when it changes
}
});
});
observer.observe(element);