viernes, 30 de diciembre de 2022

👨‍💻 Sobre el atributo loading

loading

El 12 de Febrero de 2020 el atributo loading para imágenes e iframes se hizo por fin parte del estándar HTML. Si bien ya se podía utilizar activando un par de flags en el navegador Chrome, hasta ahora no formaba parte de las funcionalidades que soporta el navegador.

chrome://flags/#enable-lazy-image-loading
chrome://flags/#enable-lazy-frame-loading

¿Que soporte tiene por los navegadores?

Ahora bien, aunque se trate de un estándar HTML, todavía no tiene el soporte de todos los navegadores can I use
Fuente: caniuse.com

Por lo que si lo quieres utilizar, todavía necesitas de un polyfill y un poco de JavaScript.

El concepto Lazy Loading (Carga Diferida)

La página web promedio pesa alrededor de 3719 kB con imágenes y videos ocupando casi el 78% del peso total, de acuerdo al HTTP Archive. Esos son muchos bytes que el navegador de un visitante tiene que descargar y visualizar, y todas las tendencias apuntan a páginas aún más grandes y un incremento en el uso de imágenes para el futuro. WordPress está liderando la carga cuando se trata de compartir archivos multimedia e incorporando archivos multimedia en el diseño del sitio.

Sin embargo, todos esos recursos pesados hacen que descargar una página web, sea una experiencia costosa para los usuarios que tienen que esperar para descargar grandes archivos – incluyendo archivos que al inicio no son visibles – antes de ver la página.

Carga diferida es una técnica de optimización que carga contenido visible, pero retrasa la carga y la versión del contenido que aparece debajo del pliegue. Es el tipo de cosas que a Google le emociona, y es una técnica que debería considerar si sus publicaciones y páginas incluyen muchos videos e imágenes de alta resolución.

Carga diferida funciona así:

  • El navegador construye la página web DOM sin descargar imágenes y precargar videos.
  • JavaScript es usado para determinar que imágenes descargar y que videos precargar, basado en el contenido que es inicialmente visible cuando la página carga. Estas imágenes y videos son descargados y precargados como sea apropiado.
  • El descargar y la versión de videos adicionales es retrasado hasta que el visitante del sitio baje a lo largo de la página y un contenido adicional aparece.

El resultado final es que las imágenes no son descargadas y los videos cargados hasta que realmente sean necesarios. Esto puede brindar un impulso significativo en el desempeño para sitios que incluyan muchas imágenes de alta resolución y videos.

Carga diferida puede traer un profundo impacto en la velocidad del sitio si usted utiliza muchas imágenes. 🚀

¿Las imágenes y videos realmente hacen más lentos a los sitios web?

Antes que nada y antes de cargar imágenes a WordPress asegúrese de que estén optimizados.

Necesitamos una calificación base para que podamos ver el impacto al agregar nuevas imágenes y videos. No tiene sentido arreglar un problema, si en realidad no hay un problema que haya que arreglar. Para probar las cosas, yo preparo una instalación estándar de WordPress en una cuenta de hosting de Kinsta. TwentySixteen es el tema activo y no se han implementado plugins de optimización ni técnicas como el almacenamiento en caché.

Así es como Pingdom website speed test califica el sitio antes de agregar cualquier imagen o video.

Prueba de velocidad sin imágenes o videos
Prueba de velocidad sin imágenes o videos

Como puede ver, la página es muy liviana, pesa menos de 155 kb y carga en menos de medio segundo. Es difícil encontrar una falla con estos resultados. ¿Qué pasa si cargamos la página con imágenes grandes y videos de YouTube?

loading
Prueba de velocidad sin el plugin de carga diferida

El tamaño de la página subió a 1.7 MB y el tiempo de carga se ha triplicado, por tan sólo debajo de los 1.3 segundos. TwentySixteen es un tema liviano y bien programado, así que incluso con una media docena de imágenes y videos de YouTube, el sitio sigue siendo bastante liviano y se carga súper rápido. Sin embargo, podemos ver que, al agregar imágenes y videos, ha hecho mucho mayor el tamaño de la página y a reducido su velocidad considerablemente.

Cómo utilizar lazy-loading nativo para imágenes

Para utilizar el lazy-loading nativo de HTML, lo más apropiado primero es detectar si el navegador soporta la funcionalidad. Si no lo hace, entonces recurríamos a un script de terceros, librería o una implementación propia en el caso de que queramos ofrecer la misma experiencia a todos los navegadores.

Para ello, con el siguiente pequeño script realizamos la comprobación:

<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, no tenemos más que implementar el atributo loading dentro del tag img de HTML

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

Aquí tienes 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.

En éste vídeo te dejo una demo:

🔴 Suscríbete al Canal

¿Y si mi navegador no soporta el lazy-load nativo?

Si el navegador aún no implementa este nuevo estándar, gracias a la comprobación que hemos hecho antes, podemos hacer que se cargue una librería externa que actúe como polyfill y permita recrear el lazy-load veamos un ejemplo:


<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 fancy 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>

Atributo loading

El atributo loading permite al navegador retrasar la carga de imáges y de iframes que están fuera de pantalla, hasta que el usuario haga scroll cerca de ellas. Éste atributo soporta 3 valores:

  • 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: Implementa el comportamiento por defecto del navegador para la carga de las imágenes. En resumen, poner auto es lo mismo que no poner el atributo loading.

En palabras sencillas, si una página web define el parámetro loading, con el valor lazy, en sus imágenes y recursos incrustados, su velocidad de respuesta será mayor, pues solo presentará los primeros elementos de la vista actual (above de fold).

Luego, a medida que el usuario navegue en la página, por scroll, el navegador irá solicitando los nuevos recursos.

El mejor ejemplo es Instagram: a medida que el usuario se desplaza, las imágenes van apareciendo. Esto, innegablemente, mejora los tiempos de respuesta.

 Precaución: Aunque está disponible en Chromium, el auto no se menciona en la especificación. Dado que puede estar sujeto a cambios, recomendamos no usarlo hasta que sea incluido.

Limite de distancia desde la ventana gráfica

Todas las imágenes que están en la mitad superior de la página (above the fold), es decir, que se pueden ver inmediatamente sin desplazarse (sin hacer scroll), se cargan automáticamente. Las que están muy por debajo de la ventana gráfica del dispositivo, no se cargan hasta que el usuario llega a ellas haciendo scroll, es decir, cuando solo se cargan cuando el usuario se desplaza cerca de ellas.

La implementación de Chromium de la carga diferida intenta garantizar que las imágenes fuera de la pantalla se carguen lo suficientemente temprano para que estén listas una vez que el usuario se desplaza cerca de ellas. Al buscar imágenes cercanas antes de que se vuelvan visibles en la ventana gráfica, maximizamos la posibilidad de que ya estén cargadas cuando se vuelven visibles.

En comparación con las bibliotecas de carga diferida de JavaScript, los limites para obtener imágenes que se desplazan a la vista pueden considerarse como conservadores. Chromium busca alinear mejor estos limites con las expectativas de los desarrolladores.

El limite de distancia calculada no es fijo y varía en función de varios factores:

  • El tipo de recurso de imagen que se está recuperando (si es una imagen o un iframe con un video por ejemplo),
  • Si está habilitado el modo lite en Chrome para Android,
  • el tipo de conexión efectiva (3G, 4G, HSDPA,...)

Puede encontrar los valores predeterminados para los diferentes tipos de conexiones efectivas en la fuente de Chromium. Estos números, e incluso el enfoque de buscar solo cuando se alcanza una cierta distancia desde la ventana gráfica, pueden cambiar en un futuro cercano a medida que el equipo de Chrome mejora la heurística para determinar cuándo comenzar a cargar.

Los experimentos realizados con Chrome en Android sugieren que en 4G, el 97,5% de las imágenes de la mitad inferior de la página que se cargan de forma diferida se cargaron por completo en un plazo de 10ms desde que se hicieron visibles. Incluso en redes 2G lentas, el 92,6% de las imágenes de la mitad inferior de la página se cargaron por completo en 10ms. Esto significa que la carga diferida a nivel del navegador ofrece una experiencia estable con respecto a la visibilidad de los elementos que se desplazan hacia la vista.

¿El nuevo atributo loading solo sirve para imágenes?

El nuevo atributo no sólo sirve para el tag img de HTML. También se puede utilizar para imágenes con srcset, dentro de picture y en iframes. Aquí tienes algunos ejemplos:


<!-- Lazy-loading en imágenes con picture. Se implementa dentro de <img> como fallback. -->
<picture>
  <source
    media="(min-width: 40em)"
    srcset="img-big.jpg 1x, img-big-hd.jpg 2x"
  />
  <source srcset="img-small.jpg 1x, img-small-hd.jpg 2x" />
  <img src="img-fallback.jpg" loading="lazy" />
</picture>

<!-- Lazy-loading en imágenes que tienen un srcset -->
<img
  src="small.jpg"
  srcset="img-large.jpg 1024w, img-medium.jpg 640w, img-small.jpg 320w"
  sizes="(min-width: 36em) 33.3vw, 100vw"
  loading="lazy"
/>

<!-- Lazy-loading en iframes  -->
<iframe src="video-player.html" loading="lazy"></iframe>


Tabla de ventajas e inconvenientes del lazy loading

Ventajas Inconvenientes
Mejora del rendimiento Puede afectar la experiencia del usuario: por ejemplo, no es posible dar vuelta atrás en caso de estructura de página desfavorable
Reducción del tráfico en el host Requiere código adicional cuando se incorpora con JavaScript
  Pueden ser necesarias bibliotecas externas
  Para integrarlo con JavaScript, se requiere que los usuarios admitan scripts
Fuente: https://www.ionos.es/

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.

Lazy Loading permite que el sitio web mejore su velocidad de respuesta, gracias a la carga diferida de sus imágenes y recursos incrustados (iframe)



Bibliografía:


https://carlosazaustre.es

https://kinsta.com/

https://web.dev/

https://www.ionos.es/

https://e-lexia.com/



Complementarios:


https://www.itdo.com/

https://www.crehana.com/

https://www.solucionex.com/