Command Palette

Search for a command to run...

Intersection Observer API: Detección Eficiente de Visibilidad

Aprende a detectar cuando elementos entran o salen del viewport sin usar polling, optimizando lazy loading, infinite scroll y animaciones al scroll.

Lectura: 12 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • Intersection Observer detecta visibilidad de elementos sin eventos de scroll
  • Usa threshold para definir qué porcentaje debe ser visible
  • rootMargin permite ajustar el área de detección (como padding)
  • disconnect() es CRÍTICO para evitar memory leaks
  • Ideal para lazy loading, infinite scroll y animaciones al scroll

Introducción a Intersection Observer

Detectar si un elemento es visible en la pantalla ha sido tradicionalmente una tarea costosa en JavaScript. Los desarrolladores solían usar eventos de scroll combinados con getBoundingClientRect() en un loop, lo que causaba problemas de rendimiento significativos, especialmente en dispositivos móviles.

Intersection Observer API resuelve este problema de forma nativa, proporcionando una API asíncrona y eficiente que notifica cuando un elemento entra o sale de una región específica (el viewport o un elemento contenedor). Es fundamental para implementar lazy loading, infinite scroll, animaciones al scroll y muchas otras interacciones modernas.

¿Por qué no usar eventos de scroll?

Los eventos de scroll se disparan cientos de veces por segundo durante el scroll. Combinar esto con getBoundingClientRect() (que fuerza un reflow del DOM) crea una combinación desastrosa para el rendimiento. Intersection Observer usa callbacks asíncronos y no bloquea el hilo principal.

¿Qué es Intersection Observer?

Intersection Observer es una API del navegador que permite observar de forma asíncrona cambios en la intersección de un elemento target con un elemento ancestor o con el viewport del documento. A diferencia de los eventos de scroll, esta API está optimizada para rendimiento y usa callbacks eficientes que no bloquean el renderizado.

El observer notifica cuando el porcentaje de intersección cruza uno de los umbrales (thresholds) configurados. Por ejemplo, puedes configurar que se notifique cuando el elemento esté 50% visible, o cuando cualquier parte del elemento entre en el viewport.

  • No requiere polling ni eventos de scroll constantes
  • Soporta múltiples umbrales de detección (thresholds)
  • Permite definir un contenedor personalizado (root)
  • Usa rootMargin para ajustar el área de detección
  • Es asíncrono y no bloquea el hilo principal

Crear un Observer Básico

Para crear un Intersection Observer, necesitas proporcionar una función callback que se ejecutará cada vez que ocurra una intersección, y opcionalmente un objeto de configuración con opciones como threshold, root y rootMargin.

observer-basico.js
Loading code...

El callback recibe un array de entradas (IntersectionObserverEntry), donde cada entrada representa un elemento observado. La propiedad isIntersectingindica si el elemento está actualmente intersectando con el área de observación.intersectionRatio muestra qué porcentaje del elemento es visible (0 a 1).

Mejor práctica: Un solo observer para múltiples elementos

En lugar de crear un observer por cada elemento, crea un solo observer y observa múltiples elementos. Esto es más eficiente y el mismo callback manejará todos. Usa entry.target para identificar qué elemento causó la intersección.

Opciones de Configuración

El objeto de configuración del Intersection Observer tiene tres propiedades clave que controlan cómo se detectan las intersecciones. Comprender estas opciones es fundamental para implementar comportamientos precisos y eficientes.

opciones-configuracion.js
Loading code...

threshold define qué porcentaje del elemento debe ser visible para disparar el callback. Puedes especificar múltiples valores (ej: [0, 0.25, 0.5, 0.75, 1]) para notificar en múltiples puntos. rootMargin funciona como el padding de CSS y permite extender o reducir el área de detección. rootespecifica el elemento contenedor; si es null, usa el viewport del documento.

Advertencia: root personalizado requiere overflow

Si especificas un elemento root personalizado (no null), ese elemento DEBE tener una propiedad overflow establecida (scroll, auto o hidden) para que el navegador pueda calcular correctamente las intersecciones. Sin esto, el observer no funcionará como esperas.

Lazy Loading de Imágenes

El caso de uso más común de Intersection Observer es el lazy loading de imágenes. En lugar de cargar todas las imágenes al inicio, cargas solo las que están cerca del viewport, mejorando significativamente el tiempo de carga inicial.

lazy-loading.js
Loading code...

Este patrón usa data-src para almacenar la URL real de la imagen y la carga solo cuando el elemento entra en el viewport. Una vez cargada, el observer deja de observar ese elemento con unobserve(), liberando recursos. El atributo loading="lazy" nativo es una alternativa más simple, pero Intersection Observer ofrece más control y compatibilidad con navegadores más antiguos.

Infinite Scroll

Infinite scroll carga más contenido automáticamente cuando el usuario llega al final de la página. Intersection Observer es perfecto para esto, ya que puedes observar un elemento "sentinela" al final del contenido y cargar más cuando se vuelve visible.

infinite-scroll.js
Loading code...

El elemento sentinela es un div vacío al final del contenido. Cuando el usuario hace scroll y este elemento entra en el viewport, se carga más contenido y el sentinela se mueve al nuevo final. Es importante manejar el caso donde no hay más contenido para evitar llamadas innecesarias.

Advertencia: Memory leaks con infinite scroll

En infinite scroll, es fácil crear memory leaks si no desconectas el observer cuando el usuario navega away de la página. Siempre llama a disconnect()en el evento beforeunload o cuando el componente se desmonta.

Casos de Uso Avanzados

Más allá de lazy loading e infinite scroll, Intersection Observer tiene múltiples aplicaciones en interfaces modernas. Estos patrones demuestran la versatilidad de la API para crear experiencias de usuario más fluidas y performantes.

  • Animaciones que se activan al entrar en el viewport
  • Detectar cuando un video sale de pantalla para pausarlo
  • Implementar skeleton screens que se reemplazan al cargar
  • Lazy loading de componentes en aplicaciones SPA
  • Tracking de visibilidad para analíticas (viewability)
animaciones-scroll.js
Loading code...

Este ejemplo muestra cómo activar animaciones CSS cuando los elementos entran en el viewport. La clase visible se añade cuando el elemento intersecta, permitiendo transiciones suaves. El patrón de observar una sola vez es común para animaciones de entrada que no necesitan repetirse.

Tracking de visibilidad para analíticas

Para tracking de analíticas, usa un threshold de 0.5 (50%) para considerar que un anuncio o contenido fue "visto". Esto es más preciso que simplemente cargar el contenido, ya que refleja visibilidad real del usuario. Combínalo con tiempo mínimo de visibilidad para mayor precisión.

Errores Comunes

Al trabajar con Intersection Observer, hay varios errores comunes que pueden causar problemas de rendimiento, bugs sutiles o comportamiento inesperado. Conocer estos patrones problemáticos te ayudará a evitarlos en tu código.

error-no-disconnect.js
Loading code...

No desconectar el observer cuando ya no es necesario es uno de los errores más comunes. Esto causa memory leaks porque el observer sigue ejecutando callbacks incluso después de que los elementos fueron removidos del DOM o el usuario navegó a otra página.

error-threshold-incorrecto.js
Loading code...

Usar thresholds incorrectos puede causar callbacks que no se disparan cuando esperas. Por ejemplo, threshold: 1 requiere que el elemento esté 100% visible, lo cual es raro en la práctica. Para detectar cualquier visibilidad, usa threshold: 0.

error-root-margin-negativo.js
Loading code...

rootMargin negativo reduce el área de detección, lo cual puede ser útil para cargar contenido antes de que sea completamente visible. Sin embargo, si el valor es demasiado grande, el contenido nunca se cargará. Usa valores moderados como "-100px" o "-200px" para preloading inteligente.

Resumen: Intersection Observer API

Conceptos principales:

  • Intersection Observer detecta visibilidad de forma asíncrona
  • threshold define el porcentaje de visibilidad para notificar
  • rootMargin ajusta el área de detección (como padding)
  • root especifica el contenedor de observación
  • disconnect() detiene todas las observaciones activas

Mejores prácticas:

  • Usa un solo observer para múltiples elementos
  • Siempre desconecta el observer cuando ya no se necesite
  • Usa threshold: 0 para detectar cualquier visibilidad
  • Combina con data attributes para lazy loading
  • Implementa unloading para evitar memory leaks