Detectando Quando Elementos Entram no Viewport com Intersection Observer

Rastrear a visibilidade de elementos com event listeners de scroll pode prejudicar drasticamente a performance do seu site. Cada scroll dispara múltiplos eventos, cada um chamando getBoundingClientRect()
e forçando reflows caros no navegador. A API Intersection Observer resolve esse problema de forma elegante, fornecendo otimização nativa do navegador para detectar quando elementos entram ou saem do viewport.
Pontos-Chave
- O Intersection Observer elimina gargalos de performance causados por event listeners de scroll
- A API executa de forma assíncrona, prevenindo bloqueio da thread principal
- Um único observer pode monitorar múltiplos elementos de forma eficiente
- A otimização nativa do navegador oferece melhor performance que cálculos manuais
Por Que os Eventos de Scroll Tradicionais São Insuficientes
Event listeners de scroll disparam continuamente durante a rolagem, frequentemente acionando mais de 60 vezes por segundo. Cada event handler que chama getBoundingClientRect()
força o navegador a recalcular layouts, criando experiências de scroll travadas. Quando múltiplas bibliotecas rastreiam visibilidade independentemente—para anúncios, analytics e lazy loading—o impacto na performance se agrava dramaticamente.
A abordagem do Intersection Observer move esses cálculos para fora da thread principal, permitindo que o navegador otimize quando e como as verificações de intersecção ocorrem.
Entendendo os Fundamentos do Intersection Observer
A API Intersection Observer observa de forma assíncrona elementos-alvo cruzando fronteiras com um elemento raiz (tipicamente o viewport). Em vez de polling constante, ela te notifica apenas quando limites de visibilidade são cruzados.
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Elemento está visível');
}
});
});
observer.observe(document.querySelector('.target'));
O navegador gerencia todos os cálculos de intersecção internamente, entregando resultados através de um callback com objetos IntersectionObserverEntry
. Cada entry fornece isIntersecting
(boolean) e intersectionRatio
(porcentagem de visibilidade de 0-1).
Criando Seu Primeiro Observer
Configurar um Intersection Observer requer apenas uma função callback e configuração opcional:
const callback = (entries, observer) => {
entries.forEach(entry => {
// Propriedades-chave disponíveis
console.log({
isVisible: entry.isIntersecting,
visibilityRatio: entry.intersectionRatio,
targetElement: entry.target
});
});
};
const options = {
root: null, // viewport
rootMargin: '0px', // sem offset
threshold: 0.5 // 50% visível
};
const observer = new IntersectionObserver(callback, options);
observer.observe(document.querySelector('.target'));
O callback recebe um array de entries porque observers podem rastrear múltiplos elementos simultaneamente. O isIntersecting
de cada entry indica visibilidade atual, enquanto intersectionRatio
fornece a porcentagem precisa de visibilidade.
Configurando Opções do Observer
Três opções controlam quando os callbacks de intersecção disparam:
root: Define a área scrollável a ser observada. null
usa o viewport; qualquer elemento scrollável funciona como raiz customizada.
rootMargin: Expande ou encolhe a bounding box da raiz. Use sintaxe de margin CSS: "50px"
ou "10% 0px"
. Valores negativos encolhem; valores positivos expandem a área de detecção.
threshold: Porcentagem(ns) de visibilidade que acionam callbacks. Valor único: 0.5
(50%). Array para múltiplos gatilhos: [0, 0.25, 0.5, 0.75, 1]
.
Discover how at OpenReplay.com.
Observando Múltiplos Elementos de Forma Eficiente
Uma instância de observer pode monitorar elementos ilimitados:
const observer = new IntersectionObserver(callback, options);
const targets = document.querySelectorAll('.lazy-load');
targets.forEach(target => observer.observe(target));
// Parar de observar elementos específicos
// observer.unobserve(element);
// Parar de observar todos os elementos
// observer.disconnect();
Esse padrão maximiza a eficiência—o navegador otimiza um único observer observando centenas de elementos melhor que múltiplos observers.
Exemplos de Implementação do Mundo Real
Lazy Loading de Imagens
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imageObserver.unobserve(img);
}
});
}, { rootMargin: '50px' });
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
Disparando Animações no Scroll
const animationObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate');
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.animate-on-scroll').forEach(element => {
animationObserver.observe(element);
});
Auto-Play de Vídeos em Visualização
const videoObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const video = entry.target;
if (entry.isIntersecting) {
video.play();
} else {
video.pause();
}
});
}, { threshold: 0.5 });
document.querySelectorAll('video').forEach(video => {
videoObserver.observe(video);
});
Conclusão
A API Intersection Observer transforma a detecção de viewport de um gargalo de performance em uma funcionalidade otimizada do navegador. Ao substituir event listeners de scroll por intersection observers, você elimina o bloqueio da thread principal enquanto ganha controle de visibilidade mais preciso. Comece a migrar seu código de visibilidade baseado em scroll hoje—os navegadores dos seus usuários vão agradecer.
FAQs
Sim, simplesmente chame observer.observe() nos novos elementos após eles serem adicionados ao DOM. A mesma instância do observer pode monitorar elementos adicionados a qualquer momento durante o ciclo de vida da página.
O callback dispara imediatamente com o estado atual de intersecção do elemento. Isso garante que você sempre saiba o status inicial de visibilidade sem precisar de verificações separadas.
Verifique se entry.isIntersecting é false no seu callback. O observer te notifica tanto quando elementos entram quanto saem da área observada baseado nas suas configurações de threshold.
Navegadores modernos o suportam nativamente. Para navegadores mais antigos como Internet Explorer, use o polyfill oficial do W3C que fornece funcionalidade idêntica através de JavaScript.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.