Desarrollo web

Lazy loading de imágenes en HTML: loading="lazy", fetchpriority y decoding

Cómo activar la carga diferida con loading="lazy", por qué no debes aplicarla a la imagen principal y cómo combinarla con fetchpriority y decoding.

El lazy loading (carga diferida) de imágenes consiste en no descargar una imagen hasta que esté cerca de entrar en pantalla. En HTML se activa añadiendo loading="lazy" a la etiqueta <img>, sin JavaScript ni librerías, y lo soportan todos los navegadores actuales. La regla más importante es no aplicarlo a la imagen principal de la página (la que cuenta para el LCP), que debe cargarse cuanto antes.

En este artículo verás cómo funciona el atributo, cómo combinarlo con fetchpriority y decoding, qué errores lo convierten en una penalización en lugar de una mejora y cómo comprobar que está funcionando.

Qué hace exactamente loading=“lazy”

Cuando el navegador encuentra una imagen con loading="lazy", en lugar de descargarla inmediatamente espera a que el usuario se acerque a ella al hacer scroll. La distancia a partir de la cual empieza la descarga la decide el navegador (en Chrome depende del tipo de conexión y suele ser de varios cientos de píxeles), de modo que normalmente la imagen ya está lista cuando aparece.

<img src="/img/grafico.webp" alt="Gráfico de visitas mensuales" width="800" height="500" loading="lazy" decoding="async" />

El atributo admite dos valores:

  • lazy: difiere la carga hasta que la imagen esté cerca del viewport.
  • eager: carga inmediatamente (es el comportamiento por defecto si no indicas nada).

Según Can I use, el soporte es universal en navegadores modernos: Chrome desde la versión 77, Firefox desde la 75, Safari desde la 15.4 y Edge desde la 79. En un navegador antiguo que no lo entienda, el atributo simplemente se ignora y la imagen se carga como siempre; no hay riesgo de que no se muestre.

Por qué importa: menos bytes y mejor LCP

Una página con veinte imágenes que solo muestra tres en pantalla descarga, sin lazy loading, las veinte. Con loading="lazy" en las que están fuera de pantalla, descarga tres y el resto a medida que hagan falta. El resultado es menos transferencia, menos competencia por el ancho de banda y, lo más relevante para los Core Web Vitals, que los recursos críticos (la imagen principal, las fuentes, el CSS) llegan antes.

La regla de oro: no diferir la imagen del LCP

El LCP (Largest Contentful Paint) mide cuándo se pinta el elemento más grande visible. En la mayoría de artículos y páginas de producto ese elemento es la imagen destacada. Si le pones loading="lazy", el navegador la trata como no prioritaria y la carga más tarde de lo que podría: el LCP empeora. La documentación de web.dev sobre optimización del LCP es explícita en este punto.

Lo correcto para la imagen principal es lo contrario:

<img src="/img/portada.webp" alt="Portada del artículo" width="1200" height="630" loading="eager" fetchpriority="high" decoding="async" />
  • loading="eager" (o simplemente omitir el atributo) para que se descargue de inmediato.
  • fetchpriority="high" para indicar al navegador que esa imagen es más importante que el resto de recursos de la misma categoría.

Regla práctica: la imagen que ya se ve al cargar la página, sin hacer scroll, no se difiere. Las demás, sí.

fetchpriority y decoding: los otros dos atributos

fetchpriority

fetchpriority ajusta la prioridad relativa de una petición. Acepta high, low y auto. Úsalo con high en la imagen del LCP y, si quieres, con low en imágenes decorativas de un carrusel que no se ven al inicio. No tiene sentido ponerlo en todas las imágenes: si todo es prioritario, nada lo es.

decoding

decoding="async" permite al navegador descodificar la imagen fuera del hilo principal, de modo que el resto de la página no espera. Es seguro usarlo en prácticamente todas las imágenes de contenido. La alternativa sync solo tiene sentido en casos muy concretos en los que la imagen deba aparecer exactamente en el mismo frame que el texto que la rodea.

Siempre con width y height

Lazy loading y dimensiones van juntos. Si el navegador no sabe qué tamaño ocupará una imagen que aún no ha descargado, reservará cero píxeles y, cuando llegue, empujará el contenido hacia abajo. Eso es un salto de maquetación (CLS), otro de los Core Web Vitals. Declara siempre width y height con las dimensiones reales de la imagen; el CSS puede escalarla (max-width: 100%; height: auto;) sin perder la proporción.

Imágenes de fondo CSS e iframes

El atributo loading solo existe en <img> e <iframe>. Las imágenes de fondo definidas en CSS (background-image) no se pueden diferir con él; si necesitas hacerlo, tendrás que usar JavaScript con IntersectionObserver o replantear si esa imagen debería ser un <img> dentro del HTML (que, además, es mejor para la accesibilidad y el SEO).

Para iframes (vídeos incrustados, mapas) funciona igual:

<iframe src="https://www.youtube-nocookie.com/embed/ID" title="Título del vídeo" width="560" height="315" loading="lazy"></iframe>

Errores habituales

  1. Poner loading="lazy" a todas las imágenes de forma automática. Muchos plugins de WordPress lo hacen. Revisa que la imagen destacada quede excluida.
  2. Sin width ni height. Produce CLS y, en algunos navegadores, hace que la carga diferida se comporte peor porque no pueden calcular la distancia al viewport.
  3. Imágenes ocultas con display: none. Siguen descargándose en cuanto el navegador decide que están “cerca”. Si no se van a mostrar, no las incluyas en el HTML.
  4. Confiar en que lazy loading arregla imágenes enormes. Diferir la carga no reduce el peso. Primero redimensiona y convierte a WebP o AVIF; después difiere.

Cómo comprobar que funciona

Abre las herramientas de desarrollo del navegador, pestaña Red (Network), filtra por imágenes y recarga la página sin hacer scroll. Solo deberían aparecer las imágenes visibles. Al bajar, verás cómo las demás se van solicitando. En Lighthouse, la auditoría “Defer offscreen images” dejará de aparecer cuando todo esté correcto, y “Largest Contentful Paint image was lazily loaded” te avisará si has diferido la imagen principal por error.

Conclusión

loading="lazy" es la forma más sencilla y segura de reducir el peso inicial de una página con muchas imágenes: un atributo, sin JavaScript y con soporte universal. Para que sea una mejora real, acompáñalo de width y height, usa decoding="async", y deja la imagen principal fuera con loading="eager" y fetchpriority="high". Diferir lo que no se ve y priorizar lo que sí es, en esencia, toda la estrategia.

Fuentes y referencias

  1. MDN: Lazy loading developer.mozilla.org
  2. MDN: <img> — atributo loading developer.mozilla.org
  3. web.dev: Browser-level image lazy loading for the web web.dev
  4. web.dev: Optimize Largest Contentful Paint web.dev
  5. MDN: fetchpriority developer.mozilla.org
  6. Can I use: Lazy loading via attribute for images & iframes caniuse.com

Herramientas relacionadas

Herramientas gratuitas de AIMRAN Tools que funcionan en tu navegador, sin registro.

Ver todas las herramientas
Artículos de Desarrollo web