Carga de imágenes web más optimizada en 2021



En este artículo, compartiré 8 técnicas para optimizar la carga de imágenes que reducen el ancho de banda de red requerido y la carga del procesador cuando se muestran en la pantalla. A continuación, se muestran algunos ejemplos de HTML anotado para facilitar su reproducción. Algunas técnicas se conocen desde hace mucho tiempo y algunas han aparecido relativamente recientemente. Idealmente, su mecanismo de publicación de documentos web favorito (como un CMS, un generador de sitios estáticos o un marco de aplicación web) debería hacer todo esto de inmediato.



En conjunto, las técnicas optimizan todos los elementos de Google Core Web Vitals al:





Para ver todas las técnicas en acción, eche un vistazo al código fuente para cargar esta imagen:



https://www.industrialempathy.com/img/remote/ZiClJf.jpg
<img loading="lazy" decoding="async" style="background-size: cover; background-image: none;" src="/img/remote/ZiClJf.avif" alt="Sample image illustrating the techniques outlined in this post." width="4032" height="2268">

      
      







Técnicas de optimización



Disposición Responsive



Esta sencilla técnica permite que la imagen ocupe el espacio horizontal disponible manteniendo la relación de aspecto. En 2020, los navegadores han aprendido a reservar la cantidad correcta de espacio vertical para una imagen antes de que se cargue si el elemento img



contiene atributos width



y height



. Esto evita el cambio acumulativo del diseño.



<style>
 img {
   max-width: 100%;
   height: auto;
 }
</style>
<!-- Providing width and height is more important than ever. -->
<img height="853" width="1280" … />

      
      





Representación perezosa



La segunda técnica es más complicada. El nuevo atributo CSS content-visibility: auto



le dice al navegador que no piense en colocar la imagen hasta que esté lista. Este enfoque tiene varias ventajas, la principal de las cuales es que hasta que el navegador no reciba una imagen de marcador de posición borrosa o la imagen en sí, no la decodificará, lo que ahorra recursos del procesador.



Ya no es necesario contener tamaño intrínseco



Una versión anterior del artículo explicaba cómo contain-intrinsic-size



evitar el efecto CLS al usar content-visibility: auto



. Pero en Chromium 88 esto ya no es necesario en el caso de imágenes para las que width



y height



. A partir del 27 de enero de 2021, content-visibility: auto



aún no implementado en otros motores de navegador
, es probable que sigan el ejemplo de Chromium. Así que sí, ¡ahora es mucho más fácil!



<style>
 /* This probably only makes sense for images within the main scrollable area of your page. */
 main img {
   /* Only render when in viewport */
   content-visibility: auto;
 }
</style>

      
      





AVIF



AVIF es el formato de gráficos más reciente que ha recibido soporte en los navegadores. Ahora es compatible con Chromium y por bandera en Firefox. Safari aún no funciona con él, pero dado que Apple es parte del grupo que desarrolló el formato, este navegador también debería ser compatible con AVIF en el futuro.



Este formato es notable porque es muy superior a JPEG. Y esto se compara favorablemente con el formato WebP, cuyas imágenes no siempre son más pequeñas que JPEG y que pueden incrementar el consumo de recursos por la falta de soporte para la carga progresiva.



Para implementar una extensión progresiva para AVIF, puede usar picture



.



El elemento está realmente img



anidado en picture



... Esto puede resultar confuso, porque a img



veces se le llama solución alternativa para los navegadores que no lo admiten picture



, pero de hecho este elemento solo ayuda con la selección src



y no tiene su propio diseño. Se dibujará el elemento img



y le aplicará el estilo.



Hasta hace poco, era bastante difícil implementar imágenes AVIF en el lado del servidor, pero las versiones recientes de bibliotecas como Sharp facilitaban mucho esta tarea.



<picture>
 <source
   sizes="(max-width: 608px) 100vw, 608px"
   srcset="
     /img/Z1s3TKV-1920w.avif 1920w,
     /img/Z1s3TKV-1280w.avif 1280w,
     /img/Z1s3TKV-640w.avif   640w,
     /img/Z1s3TKV-320w.avif   320w
   "
   type="image/avif"
 />
 <!-- snip lots of other stuff -->
 <img />
</picture>

      
      





Cargando el número correcto de píxeles



El código anterior tiene atributos srcset



y sizes



. Usan un selector w



para decirle al navegador qué URL tomar en función de la cantidad física de píxeles que se necesitan para representar la imagen en un dispositivo en particular. Esta cantidad depende del ancho de la imagen, que se calcula en función del atributo sizes



(que es una expresión de la consulta de medios).



Esto asegura que el navegador siempre cargará la imagen más pequeña posible, proporcionando la mejor calidad en un dispositivo en particular. Alternativamente, puede seleccionar la imagen más pequeña si el usuario ha habilitado el modo de guardado de datos.



Solución alternativa



Para los navegadores que solo admiten formatos de imagen más antiguos, puede srcset



proporcionar más elementos sin procesar con la ayuda de:



<source
 sizes="(max-width: 608px) 100vw, 608px"
 srcset="
   /img/Z1s3TKV-1920w.webp 1920w,
   /img/Z1s3TKV-1280w.webp 1280w,
   /img/Z1s3TKV-640w.webp   640w,
   /img/Z1s3TKV-320w.webp   320w
 "
 type="image/webp"
/>
<source
 sizes="(max-width: 608px) 100vw, 608px"
 srcset="
   /img/Z1s3TKV-1920w.jpg 1920w,
   /img/Z1s3TKV-1280w.jpg 1280w,
   /img/Z1s3TKV-640w.jpg   640w,
   /img/Z1s3TKV-320w.jpg   320w
 "
 type="image/jpeg"
/>

      
      





Almacenamiento en caché y URL inmutables



Incruste en la URL de la imagen un hash del número de bytes que ocupa la imagen. En el ejemplo anterior, lo hice con Z1s3TKV



. Cuando cambie la imagen, la URL también cambiará, lo que significa que puede aplicar un almacenamiento en caché infinito de imágenes. Los encabezados de almacenamiento en caché deberían verse así cache-control: public,max-age=31536000,immutable



.



immutable



Es un significado semánticamente correcto cache-control



, pero hoy en día tiene poca compatibilidad con el navegador (te estoy mirando, Chrome). max-age=31536000



- método de almacenamiento en caché alternativo durante todo el año. public



es necesario para que su CDN almacene la imagen en caché y la envíe desde el borde de la red. Pero este enfoque solo se puede utilizar si no infringe sus políticas de privacidad.



Carga lenta



Al agregar loading=«lazy»



al elemento, img



le decimos al navegador que comience a buscar la imagen solo cuando esté lista para ser renderizada.



<img loading="lazy" … />

      
      





Descifrado asincrónico



Al agregar decoding=«async»



al elemento, img



permitimos que el navegador descifre la imagen fuera del flujo principal para que este procedimiento no interfiera con el usuario. No debería haber fallas notables en esta solución, excepto que no siempre es aplicable por defecto en navegadores más antiguos.



<img decoding="async" … />

      
      





Talón borroso



Un stub difuso es una imagen en línea que le da al usuario una idea de una imagen completa que se cargará más tarde, sin transferir datos a través de la red.



https://www.industrialempathy.com/img/blurry.svg





Algunas notas de implementación:



  • El talón está alineado como background-image



    imágenes. Esta técnica le permite eliminar el segundo elemento HTML al ocultar literalmente el código auxiliar cuando se carga la imagen principal, no se necesita JavaScript.
  • El URI de datos de imagen principal se incluye en el URI de datos de imagen SVG. Esto se hace porque el desenfoque se realiza a nivel SVG y no se utiliza un filtro CSS. Es decir, el desenfoque se realiza una vez para cada imagen cuando se rasteriza con SVG, no para cada diseño. Esto ahorra recursos del procesador.


<img
 style="
     …
     background-size: cover;
     background-image:
       url('data:image/svg+xml;charset=utf-8,%3Csvg xmlns=\'http%3A//www.w3.org/2000/svg\'

xmlns%3Axlink=\'http%3A//www.w3.org/1999/xlink\' viewBox=\'0 0 1280 853\'%3E%3Cfilter id=\'b\' color-interpolation-filters=\'sRGB\'%3E%3CfeGaussianBlur stdDeviation=\'.5\'%3E%3C/feGaussianBlur%3E%3CfeComponentTransfer%3E%3CfeFuncA type=\'discrete\' tableValues=\'1 1\'%3E%3C/feFuncA%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Cimage filter=\'url(%23b)\' x=\'0\' y=\'0\' height=\'100%25\' width=\'100%25\'
       xlink%3Ahref=\'data%3Aimage/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAGCAIAAACepSOSAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAs0lEQVQI1wGoAFf/AImSoJSer5yjs52ktp2luJuluKOpuJefsoCNowB+kKaOm66grL+krsCnsMGrt8m1u8mzt8OVoLIAhJqzjZ2tnLLLnLHJp7fNmpyjqbPCqLrRjqO7AIeUn5ultaWtt56msaSnroZyY4mBgLq7wY6TmwCRfk2Pf1uzm2WulV+xmV6rmGyQfFm3nWSBcEIAfm46jX1FkH5Djn5AmodGo49MopBLlIRBfG8yj/dfjF5frTUAAAAASUVORK5CYII=\'%3E%3C/image%3E%3C/svg%3E');
   "
 …
/>

      
      





(Opcional) Optimización de JavaScript



Los navegadores pueden verse obligados a rasterizar el talón borroso incluso si la imagen ya está cargada. El problema se puede resolver eliminando la rasterización en el arranque. Además, si su imagen tiene áreas transparentes, esta optimización se vuelve obligatoria; de lo contrario, se mostrará un talón a través de la imagen.



<sript>
 document.body.addEventListener(
   "load",
   (e) => {
     if (e.target.tagName != "IMG") {
       return;
     }
     // Remove the blurry placeholder.
     e.target.style.backgroundImage = "none";
   },
   /* capture */ true
 );
</sript>

      
      





Adicionalmente



Una herramienta útil que implementa todas las optimizaciones descritas: once-blog de alto rendimiento



All Articles