Lección 4 de 410 min
Imágenes rápidas
Formatos modernos, imágenes responsive con srcset y sizes, Image CDN y cómo priorizar la imagen principal.
En la mayoría de las webs, las imágenes son lo que más pesa, y la foto principal suele ser el elemento LCP. Una ficha de producto con seis fotos JPEG de 2000 píxeles de ancho puede descargar varios megas en un móvil cuya pantalla mide 400 píxeles, y tardar segundos en mostrar la primera.
La buena noticia es que casi todo se arregla con HTML: elegir un formato moderno, ofrecer varios tamaños para que el navegador elija, generarlos con una Image CDN y decirle al navegador cuál es la imagen que más importa.
Elegir el formato
Formatos modernos: WebP y AVIF
La misma calidad visual en bastantes menos bytes que JPEG y PNG.
- WebP:
- AVIF:
- Basado en AV1
- Vectores:
- SVG
Durante décadas, la web ha usado JPEG para las fotos, con pérdida de calidad, y PNG para gráficos con transparencia, sin pérdida. WebP, de Google, y AVIF, basado en el códec de vídeo AV1, comprimen bastante mejor: con la misma calidad aparente, el archivo pesa menos. Los dos admiten transparencia y animación, y los soportan los navegadores modernos.
AVIF suele conseguir los archivos más pequeños, pero tarda más en codificarse. Para todo lo que se puede dibujar con formas, como iconos, logotipos o ilustraciones planas, el formato es SVG, que viste en el módulo de fundamentos: vectorial, nítido a cualquier tamaño y casi siempre más ligero.
Úsalo cuando
AVIF o WebP para fotos y gráficos de mapa de bits, con JPEG como respaldo si necesitas cubrir navegadores muy antiguos. SVG para todo lo vectorial.
Ten en cuenta
Cambiar de formato no arregla una imagen de 4000 píxeles mostrada a 400: primero, el tamaño correcto. Compara formatos con la misma calidad visual, no con el mismo número de calidad. Y sustituye los GIF animados por vídeo o por WebP animado: pesan muchísimo menos.
import sharp from "sharp";
// Un original, varios anchos y dos formatos modernos
for (const ancho of [400, 800, 1600]) {
const imagen = sharp("originales/zapatillas.jpg").resize({ width: ancho });
await imagen.clone().avif({ quality: 50 }).toFile(`dist/zapatillas-${ancho}.avif`);
await imagen.clone().webp({ quality: 75 }).toFile(`dist/zapatillas-${ancho}.webp`);
}Imágenes responsive
La idea es ofrecer varias versiones y dejar que el navegador elija, porque solo él sabe en el momento de pedir la imagen cuánto mide la pantalla y cuál es su densidad de píxeles.
srcset y sizes
Varias anchuras de la misma imagen y una pista de cuánto ocupará en pantalla.
- Descriptor:
- w (anchura real)
- Pista:
- sizes
En srcset enumeras las versiones de la imagen con su anchura real usando el descriptor w: zapatillas-400.jpg 400w, zapatillas-800.jpg 800w…. En sizes le dices al navegador qué ancho tendrá la imagen en el diseño según el tamaño de la ventana, porque necesita saberlo antes de haber descargado el CSS.
Con esos dos datos y la densidad de la pantalla, el navegador calcula cuántos píxeles necesita y elige la versión más pequeña que se verá nítida. Un móvil de 400 píxeles con pantalla de doble densidad, con una imagen a todo lo ancho, necesita unos 800 píxeles: elegirá la de 800w, no la de 1600w.
Úsalo cuando
En cualquier imagen de contenido que cambie de tamaño con la pantalla: fotos de producto, portadas de artículos, galerías.
Ten en cuenta
Sin sizes, el navegador supone que la imagen ocupa todo el ancho de la ventana y puede descargar una versión demasiado grande; y sizes debe coincidir con tu CSS. Además, srcset no comprueba si el navegador entiende el formato: para elegir entre AVIF, WebP y JPEG, usa <picture> o una Image CDN.
<img
src="zapatillas-800.jpg"
srcset="zapatillas-400.jpg 400w,
zapatillas-800.jpg 800w,
zapatillas-1600.jpg 1600w"
sizes="(min-width: 1024px) 50vw, 100vw"
width="1600" height="1200"
alt="Zapatillas rojas de running">
<!-- En escritorio ocupa media pantalla; en móvil, todo el ancho -->El elemento picture
Elegir entre formatos o entre recortes distintos de una imagen según el dispositivo.
- Usos:
- Formatos y dirección de arte
<picture> contiene varios <source> y un <img> final. El navegador recorre los <source> en orden y usa el primero que encaja. Tiene dos usos. Formatos: un <source type="image/avif">, luego otro con WebP y el <img> con JPEG como respaldo; cada navegador toma el primero que sabe mostrar.
Dirección de arte: recortes distintos según la pantalla, con el atributo media. En móvil, un primer plano vertical del producto; en escritorio, la foto panorámica con el escenario. El <img> sigue siendo obligatorio: lleva el alt, las dimensiones y los estilos, y es el elemento que realmente se muestra.
Úsalo cuando
Cuando quieras servir AVIF o WebP con respaldo sin depender de una CDN, o cuando el recorte deba cambiar según la pantalla.
Ten en cuenta
Si solo necesitas tamaños distintos de la misma imagen, basta con srcset y sizes en el <img>. Y el orden importa: el primer <source> que encaja gana, así que pon primero los más específicos.
<picture>
<!-- Dirección de arte: en móvil, un recorte vertical -->
<source media="(max-width: 600px)" srcset="portada-movil.webp" type="image/webp">
<!-- Formatos: el navegador usa el primero que entienda -->
<source srcset="portada.avif" type="image/avif">
<source srcset="portada.webp" type="image/webp">
<img src="portada.jpg" alt="Nueva colección de otoño" width="1600" height="900">
</picture>Servir y priorizar
Image CDN
Subes el original una vez y pides por URL el tamaño, la calidad y el formato.
- Negocia con:
- La cabecera Accept
- Ejemplos:
- Cloudinary, imgix, Cloudflare Images
Generar cada imagen en cinco anchuras y tres formatos a mano es tedioso, y con miles de productos, imposible. Una Image CDN, como Cloudinary, imgix, Cloudflare Images o la optimización de imágenes de Vercel, lo hace al vuelo: subes el original y pides las variantes con parámetros en la URL, como el ancho, la calidad o el recorte.
Con la opción de formato automático, la CDN mira la cabecera Accept que envía el navegador (por ejemplo, image/avif,image/webp,*/*) y devuelve el mejor formato que admite. Cada variante se genera la primera vez que alguien la pide y después se sirve desde la caché del borde.
Úsalo cuando
Cuando tienes muchas imágenes, sobre todo si las suben tus usuarios en cualquier tamaño y formato. En Angular, la directiva NgOptimizedImage incluye cargadores para varias de estas CDN y genera el srcset por ti.
Ten en cuenta
Muchas cobran por transformación o por imagen. Limita los anchos permitidos, o cualquiera podrá generar miles de variantes cambiando el número de la URL. La primera petición de cada variante tarda un poco más, porque hay que generarla.
<!-- Un solo original; cada variante se genera una vez y se cachea -->
<img
src="/cdn-cgi/image/width=800,format=auto/fotos/zapatillas.jpg"
srcset="/cdn-cgi/image/width=400,format=auto/fotos/zapatillas.jpg 400w,
/cdn-cgi/image/width=800,format=auto/fotos/zapatillas.jpg 800w,
/cdn-cgi/image/width=1600,format=auto/fotos/zapatillas.jpg 1600w"
sizes="(min-width: 1024px) 50vw, 100vw"
width="1600" height="1200" alt="Zapatillas rojas de running">
<!-- format=auto: AVIF o WebP según la cabecera Accept del navegador -->Priorizar la imagen LCP
Que el navegador descubra pronto la imagen principal y la pida antes que todo lo demás.
- Atributo:
- fetchpriority="high"
- Nunca:
- loading="lazy"
La imagen principal suele ser el elemento LCP, así que todo lo que la retrase empeora la métrica. Por defecto, los navegadores piden las imágenes con prioridad baja hasta saber que son visibles; con fetchpriority="high" le dices que esta va primero. Y nunca lleva loading="lazy".
Si la imagen no está en el HTML inicial, porque es un fondo de CSS o la inserta JavaScript, el navegador no la descubre hasta muy tarde. En ese caso, adelántala con <link rel="preload" as="image"> en el <head>. Y ponle siempre width y height, o un aspect-ratio en CSS, para que el hueco esté reservado desde el principio y nada salte al cargarla.
Úsalo cuando
En la imagen principal de cada página de entrada: la portada, la ficha de producto, la cabecera de un artículo. En Angular, el atributo priority de NgOptimizedImage hace esto por ti.
Ten en cuenta
Prioriza una o dos imágenes como mucho: si todo es prioritario, nada lo es. No precargues una imagen que ya está en el HTML, y si es responsive, usa imagesrcset e imagesizes en el preload, o el navegador puede descargar dos versiones.
<!-- La imagen principal: prioridad alta, nunca lazy y con dimensiones -->
<img src="/fotos/portada.avif" alt="Nueva colección de otoño"
width="1200" height="675" fetchpriority="high">
<!-- Si es un fondo de CSS, el navegador no la ve hasta leer el CSS:
adelántala desde el <head> -->
<link rel="preload" as="image" href="/fotos/fondo-portada.avif"
type="image/avif" fetchpriority="high">Pruébalo
Abre PageSpeed Insights con tu portada y busca qué elemento marca como LCP. Si es una imagen, comprueba en el panel Network de DevTools su prioridad y cuándo empieza a descargarse respecto al HTML.
Interactivo
Formatos de imagen
Activa o desactiva opciones para compararlas cara a cara.
| Característica | JPEG | PNG | WebP |
|---|---|---|---|
| Tipo | Mapa de bits, con pérdida | Mapa de bits, sin pérdida | Con o sin pérdida |
| Transparencia | No | Sí | Sí |
| Animación | No | Solo con APNG | Sí |
| Peso en fotos | La referencia | Muy alto | Menor que JPEG |
| Úsalo para | Fotos, como respaldo | Capturas y gráficos con texto nítido | Fotos y gráficos, por defecto |
Ponlo en práctica
Saber qué es cada cosa es la mitad del trabajo. La otra mitad es reconocer cuándo usarla.
Interactivo
¿Qué usarías?
Lee cada situación y elige la opción que mejor la resuelve. Fallar aquí no cuenta: es para practicar.
Las fotos de producto son JPEG de unos 400 kB cada una. Quieres la misma calidad visual con muchos menos bytes en todos los navegadores modernos.
Para recordar
- AVIF y WebP pesan bastante menos que JPEG y PNG con la misma calidad; para iconos y logotipos, SVG.
srcsetcon descriptoreswysizesdejan que el navegador elija el tamaño justo para cada pantalla.<picture>sirve para elegir entre formatos y para cambiar el recorte según el dispositivo.- Una Image CDN genera tamaños y formatos al vuelo y negocia el formato con la cabecera
Accept. - La imagen LCP lleva
fetchpriority="high", nuncaloading="lazy", y siemprewidthyheight.
Comprueba lo aprendido
Cuestionario
Responde las 5 preguntas para completar la lección.
1.Una imagen tiene
srcsetcon versiones de400w,800wy1600w, ysizes="100vw". ¿Cuál elegirá un móvil de 400 píxeles de ancho con pantalla de doble densidad?2.En un
<picture>, el primer<source>tienetype="image/avif"y el navegador no soporta AVIF. ¿Qué hace?3.¿Cómo sabe una Image CDN si puede enviar AVIF cuando pides el formato automático?
4.¿Qué consigue
fetchpriority="high"en la imagen principal?5.¿Para qué sirven los atributos
widthyheighten una imagen responsive?