Javascript Logo
en español

Cómo cargar mediante Lazy Loading con Javascript nativo

Medio
-
3 min. lectura

Lazy loading de imágenes es una técnica muy efectiva a la hora de optimizar el rendimiento de un sitio web. 

La técnica básicamente consiste en cargar la imagen justo cuando ésta se va a visualizar y no cuando está fuera del área de visión del usuario (viewport). Es especialmente útil cuando tenemos un sitio web con scroll infinito como puede ser aplicaciones como Instagram o facebook.

Normalmente se suelen usar librerías como yall.js o similares, pero hacerlo con Javascript nativo es una tarea sumamente sencilla que explicaremos a continuación.

Intersection Observer API

Intersection Observer es una API que provee la mayoría de los navegadores y que permite, entre otras, detectar la visibilidad de un elemento dentro del viewport. 

El funcionamiento básico es el siguiente:

const options = {
  root: null
  rootMargin: "0px",
  threshold: 1.0,
};

const observer = new IntersectionObserver(callback, options);

Como obsevamos arriba, usamos la clase IntersectionObserver a la que le pasamos una función de callback a la que se llamará cuando se cruce el umbral (threshold) que establecemos en las opciones.

Las otras dos opciones son root que establece el elemento que usamos como la raíz donde se encuentran los elementos que vamos a observar (null equivale al documento completo) y rootMargin que es un margen que podemos aplicar como cuadro delimitador. 

Una vez tenemos nuestro observer, aplicaremos éste a los elementos del DOM que necesitemos (estos elementos deben estar dentro del root

const target = document.querySelector(".item");
observer.observe(target);

De esta manera, nuestro callback se ejecutará cuando el 100% del elemento observado (threshold: 1.0) sea visible en el viewport.

Creando nuestro Lazy Loading

Una vez que ya conocemos el funcionamiento de Intersection Observer ya podemos hacer que nuestras imágenes se carguen una vez están en el área visible.

Partamos de un listado de imágenes en nuestro HTML con el siguiente código:

<div class="container">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=1">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=2">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=3">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=4">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=5">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=6">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=7">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=8">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=9">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=10">
  <img class="lazy" data-src="https://picsum.photos/400/400?random=11">
</div>

Fíjate bien que no hemos usado el atributo src de la imagen, por lo que las imágenes por defecto no se cargarán. 

A continuación pasamos a observar todos los elementos con clase lazy y ejecutamos un callback que nos creará el atributo src a partir de lo que ya tenemos en data-src.

const options = { threshold: 0.1 };

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const image = entry.target;
      image.src = image.dataset.src; 
      observer.unobserve(image); 
    }
  });
}, options);

const lazyImages = document.querySelectorAll('.lazy');
lazyImages.forEach(image => observer.observe(image));

En el código de arriba, iniciamos el observador con un umbral del 10%, es decir, cuando el 10% del elemento está en el área de visión se ejecutará el callback. Como observarás solo le hemos pasado la propiedad threshold al observer. Esto es porque root por defecto es todo el documento que es justo lo que necesitamos observar y no queremos aplicar ningún margen alrededor de nuestro root. 

Además de las opciones, a la API de Intersection Observer le pasamos una función de callback que será la que se llame cuando crucemos el umbra. En ésta función evaluamos las entradas (entry) que han cruzado el umbral y le creamos a éstas el atributo src a partir  de los datos del atributo data-src.

Por último dejamos de observar este elemento ya que no tenemos intención de cargarla de nuevo una vez ya ha sido cargada. 

Finalmente, con querySelector seleccionamos todos los elementos del DOM que contengan la clase .lazy y a estos elementos le asociamos el observer que habíamos definido previamente. 

Como ves, es bastante sencillo crear un Lazy Loading sin requerir de bibliotecas adicionales. 

Si quieres conocer algo más de la API de Intersection Observer puedes consultar una extensa documentación aqui