Utilizar Lazy loading de manera estándar

What-Is-Lazy-Loading.jpeg
Solucionex
10
Nov 21

Hasta principios de 2020 el atributo loading para imágenes e iframes no era parte del estándar HTML pese a existir un "flag" en Chrome que permitía activarlo. Pese a que actualmente sea parte del estándar, todavía no tiene soporte en todos los navegadores:

Soporte en navegadores attr loading

 

Por ello si queremos utilizarlo, por ahora, necesitamos utilizar algún polyfill + JS.

Cómo utilizar el atributo loading nativo para imágenes

Para utilizar lazy-loading nativo, lo más apropiado en primer lugar es comprobar que el navegador soporta dicha funcionalidad. De no hacerlo deberíamos recurrir a algún script/libería que nos "emule" la misma funcionalidad.

Para ello bastaría con utilizar un pequeño script:

<script>
  if ("loading" in HTMLImageElement.prototype) {
    console.log("El navegador soporta `lazy-loading`...");
  } else {
    console.log("`lazy-loading` no soportado...");
  }
</script>

Si el navegador lo soporta bastaría con implementar le attr loading dentro en la etiqueta de la imagen (img):

<img loading="lazy" src="https://placekitten.com/441/441" width="320" height="80" />

Aquí un ejemplo llamando al API de placekitten para mostrar 50 imágenes (de gatos). El código HTML sería el siguiente:

<!DOCTYPE html>
<html lang="es">
  <head>
    <title>Lazy Loading Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta charset="UTF-8" />
  </head>

  <body>
    <img
      loading="lazy"
      src="https://placekitten.com/400/400"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/401/401"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/402/402"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/403/403"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/404/404"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/405/405"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/406/406"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/407/407"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/408/408"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/409/409"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/410/410"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/411/411"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/412/412"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/413/413"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/414/414"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/415/415"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/415/415"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/420/420"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/421/421"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/422/422"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/423/423"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/424/424"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/425/425"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/426/426"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/427/427"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/428/429"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/430/430"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/431/431"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/432/432"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/433/433"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/434/434"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/435/435"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/436/436"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/437/437"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/438/438"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/439/439"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/440/440"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/441/441"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/442/442"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/443/443"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/444/444"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/445/445"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/446/446"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/447/447"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/448/448"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/449/449"
      width="320"
      alt=""
    />
    <img
      loading="lazy"
      src="https://placekitten.com/450/450"
      width="320"
      alt=""
    />
    <script>
      if ("loading" in HTMLImageElement.prototype) {
        console.log("Browser support `loading`...");
      } else {
        console.log("Not supported");
      }
    </script>
  </body>
</html>

Si probamos este código en un navegador, y abrimos las Developer Tools en la pestaña de Network veremos que las primeras son cargadas automáticamente, pero a medida que hacemos scroll por la página, el resto se va descargando poco a poco.

Gif lazy loading

Que hacer en caso de que nuestro script diga que nuestro navegador no acepta lazy-loading de forma nativa

Si tras la comprobación nos percatamos de que nuestro navegador no acepta lazy-loading de forma nativa, necesitaremos recurrir a una librería de terceros a modo de polyfill. Aquí un ejemplo de ello:

<img data-src="image-gato1.jpg" loading="lazy" alt=".." class="lazyload" />
<img data-src="image-gato2.jpg" loading="lazy" alt=".." class="lazyload" />
<img data-src="image-gato3.jpg" loading="lazy" alt=".." class="lazyload" />

<script>
  if ("loading" in HTMLImageElement.prototype) {
    // Si el navegador soporta lazy-load, tomamos todas las imágenes que tienen la clase
    // `lazyload`, obtenemos el valor de su atributo `data-src` y lo inyectamos en el `src`.
    const images = document.querySelectorAll("img.lazyload");
    images.forEach((img) => {
      img.src = img.dataset.src;
    });
  } else {
    // Importamos dinámicamente la libreria `lazysizes`
    let script = document.createElement("script");
    script.async = true;
    script.src =
      "https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.2.0/lazysizes.min.js";
    document.body.appendChild(script);
  }
</script>

En este ejemplo te habrás percatado de que en los tags img no tenemos el atributo src si no uno llamado data-src esto lo hacemos para que funcione tanto de forma nativa como para la librería lazysizes que busca la imagen dentro de ese data-atribute

Si quieres ser más elegante puedes recorrer a un import dinámico de ésta manera:

...
<script>
  (async () => {
    if ("loading" in HTMLImageElement.prototype) {
      const images = document.querySelectorAll("img.lazyload");
      images.forEach((img) => {
        img.src = img.dataset.src;
      });
    } else {
      // Importamos dinámicamente la libreria `lazysizes`
      const lazySizesLib = await import("/lazysizes.min.js");
      // Se inicia lazysizes (lee el atributo `data-src` y la clase `lazyload`)
      lazySizes.init();
    }
  })();
</script>

Posibles valores del atributo loading

  • lazy: Retrasa la carga de la imagen hasta que el usuario alcanza con el scroll una distancia calculada desde el viewport.
  • eager: Carga la imagen inmediatamente, sin importar donde está situada o colocada en la pantalla. En resumen, no hace lazy-loading.
  • auto es lo mismo que no poner el atributo loading.

Distancia calculada

Las imagénes que están situadas above the fold, es decir, en la vista actual sin hacer scroll son cargadas automáticamente. Las que están por debajo no se cargan hasta que el usuario llega a ellas haciendo scroll.

Esta distancia calculada depende de varios factores: El tipo de recurso (si es una imagen o un iframe con un video por ejemplo), Si está habilitado el modo lite en Chrome par Android, el tipo de conexión (3G, 4G, HSDPA,...).

Conclusión

Si tu aplicación se basa en una alta carga de imágenes, como puede ser Instagram, ésta funcionalidad te va a permitir ahorrar mucho tiempo de carga y que la experiencia de usuario sea buena. Aún queda recorrido para que sea implementada nativamente en todos los navegadores pero mientras tanto podemos usar un polyfill si la funcionalidad no está en el navegador..