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:
- minimizar los principales problemas de contenido ( pintura con contenido más grande (LCP) ) mediante la reducción de tamaño, el almacenamiento en caché y la carga diferida;
- preservación del cambio de diseño acumulativo cero ( Cambio de diseño acumulativo (CLS) );
- reduciendo el retardo de la primera entrada ( First Input Delay (FID) ) al reducir el consumo del procesador (para el hilo principal de ejecución).
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