Imágenes y rendimiento: lazy, fetchpriority y srcset

Aprende a optimizar la carga de imágenes en HTML con loading lazy, fetchpriority, decoding, srcset y el elemento picture. Mejora el rendimiento sin tocar JavaScript.

Las imágenes son, habitualmente, el recurso más pesado de una página web. HTML moderno te da atributos potentes para controlar exactamente cuándo, cómo y en qué calidad se cargan. Sin una línea de JavaScript.


loading: carga diferida nativa

El atributo loading controla cuándo el navegador descarga la imagen.

<!-- Carga inmediata (comportamiento por defecto) -->
<img src="hero.jpg" alt="Portada" loading="eager" />

<!-- Carga diferida: solo cuando esté cerca del viewport -->
<img src="foto-al-final.jpg" alt="Foto" loading="lazy" />

¿Cuándo usar lazy?

Usa loading="lazy" en todas las imágenes que no sean visibles al cargar la página: imágenes en mitad del artículo, en el footer, en galerías largas, etc.

No uses lazy en la imagen principal (el hero o la primera imagen visible). Hacerlo retrasa la carga y penaliza el LCP (Largest Contentful Paint), una métrica de Core Web Vitals.

<!-- ✅ Hero: eager (o simplemente sin el atributo) -->
<img src="hero.jpg" alt="Hero" loading="eager" />

<!-- ✅ Resto de imágenes -->
<img src="seccion-2.jpg" alt="Sección 2" loading="lazy" />
<img src="seccion-3.jpg" alt="Sección 3" loading="lazy" />

fetchpriority: controla la prioridad de descarga

El navegador decide por sí solo qué recursos descarga primero. Con fetchpriority puedes darle pistas explícitas.

<!-- Alta prioridad: imagen crítica para el LCP -->
<img src="hero.jpg" alt="Hero" fetchpriority="high" />

<!-- Baja prioridad: imagen decorativa o fuera del viewport -->
<img src="decorativa.jpg" alt="" fetchpriority="low" />

<!-- Auto: el navegador decide (comportamiento por defecto) -->
<img src="normal.jpg" alt="Imagen" fetchpriority="auto" />

El combo ideal para el hero

La imagen principal de la página debería tener siempre este combo:

<img
  src="hero.jpg"
  alt="Descripción del hero"
  loading="eager"
  fetchpriority="high"
  decoding="sync"
/>

Y el resto de imágenes:

<img
  src="contenido.jpg"
  alt="Descripción"
  loading="lazy"
  fetchpriority="low"
  decoding="async"
/>

decoding: cuándo decodificar la imagen

La decodificación de una imagen puede bloquear el hilo principal del navegador.

<!-- sync: decodifica antes de mostrar el resto de la página (hero crítico) -->
<img src="hero.jpg" alt="Hero" decoding="sync" />

<!-- async: decodifica en paralelo, sin bloquear el render -->
<img src="foto.jpg" alt="Foto" decoding="async" />

En la práctica, decoding="async" es seguro para la mayoría de imágenes.


srcset y sizes: imágenes responsivas

Una sola imagen en tamaño grande para todos los dispositivos es un desperdicio. Con srcset le dices al navegador qué versiones existen, y con sizes le dices cuánto espacio ocupa la imagen en pantalla.

<img
  src="foto-800.jpg"
  srcset="
    foto-400.jpg  400w,
    foto-800.jpg  800w,
    foto-1200.jpg 1200w
  "
  sizes="
    (max-width: 600px)  100vw,
    (max-width: 1024px) 50vw,
    800px
  "
  alt="Foto responsiva"
  loading="lazy"
/>

Cómo leer sizes:

  • En pantallas ≤ 600px → la imagen ocupa el 100% del ancho.
  • En pantallas ≤ 1024px → ocupa el 50% del ancho.
  • En el resto → ocupa exactamente 800px.

El navegador usa esta información para elegir la versión del srcset más eficiente.


<picture>: control total sobre el formato

<picture> va un paso más allá: permite servir formatos distintos según lo que soporte el navegador, y también diferentes imágenes según el tamaño de pantalla (art direction).

Servir formatos modernos con fallback

<picture>
  <!-- AVIF: el más eficiente, soporte moderno -->
  <source srcset="foto.avif" type="image/avif" />
  <!-- WebP: segunda opción, soporte amplio -->
  <source srcset="foto.webp" type="image/webp" />
  <!-- JPG: fallback universal -->
  <img src="foto.jpg" alt="Descripción" loading="lazy" />
</picture>

El navegador prueba los <source> en orden y usa el primero que soporta. El <img> es el fallback obligatorio.

Art direction: imagen diferente según el dispositivo

<picture>
  <!-- En móvil: imagen vertical recortada -->
  <source
    media="(max-width: 600px)"
    srcset="hero-mobile.jpg"
  />
  <!-- En escritorio: imagen horizontal completa -->
  <img src="hero-desktop.jpg" alt="Hero" />
</picture>

Resumen: la guía rápida

Imagenloadingfetchprioritydecoding
Hero / LCPeagerhighsync
Contenido visibleeagerautoasync
Fuera del viewportlazylowasync

¿Qué hemos aprendido?

  • loading="lazy" difiere imágenes no visibles sin nada de JavaScript.
  • fetchpriority="high" avisa al navegador de que una imagen es crítica para el LCP.
  • decoding="async" libera el hilo principal durante la decodificación.
  • srcset + sizes sirven la resolución correcta según el dispositivo.
  • <picture> permite servir formatos modernos (AVIF, WebP) con fallback automático.

Siguiente paso

En la próxima lección veremos <dialog> y la Popover API: cómo crear modales, tooltips y paneles flotantes que el navegador gestiona de forma nativa.