Cambiar tema

Guía completa de optimización de imágenes en Astro: 5 técnicas prácticas para acelerar tu sitio un 50%

Easton editorial illustration: cache waterfall instrument

El mes pasado monté un blog técnico con Astro y, al publicarlo, la carga inicial tardaba 6 segundos. Las imágenes pesaban 2-3 MB cada una y en el móvil había que esperar una eternidad para ver el contenido. Me quedé helado: el rendimiento era pésimo.

Luego dediqué dos días a estudiar la optimización de imágenes en Astro: configuración del componente Image, elección de formato, lazy loading e integración con CDN. Paso a paso, la carga inicial bajó a 1,8 s y Lighthouse pasó de 62 a 95 puntos. Ver ese 95 me emocionó de verdad.

En este artículo comparto los tropiezos y lo aprendido, incluyendo:

  • Ejemplos completos para configurar el componente Image de Astro desde cero
  • Cómo elegir entre JPEG, PNG, WebP y AVIF
  • Buenas prácticas de lazy loading
  • Pasos detallados para integrar Cloudflare CDN
  • Soluciones a problemas frecuentes

Al terminar, podrás acelerar tu sitio Astro más de un 50 %. Empecemos.

Por qué la optimización de imágenes en Astro importa tanto

Mucha gente piensa que optimizar imágenes no es tan importante: «¿qué más da esperar unos segundos?». Pero las imágenes suelen representar el 60-70 % del peso de una página y son el principal freno del rendimiento.

En mi blog anterior, una portada sin comprimir pesaba 2,5 MB; con unas capturas más, la página superaba fácilmente 5-6 MB. Solo esperar las imágenes llevaba varios segundos y la tasa de rebote era alarmante.

Google exige tiempos de carga estrictos para las imágenes

En Core Web Vitals, Google mide el LCP (Largest Contentful Paint, pintado del contenido principal). En la práctica, es el tiempo hasta que el contenido principal termina de cargar. Google exige un LCP por debajo de 2,5 s; por encima de 4 s se considera deficiente.

En la mayoría de sitios, el LCP lo marca la portada o la imagen del primer pantallazo. Si las imágenes cargan lento, el LCP sube y el SEO se resiente.

Resultados reales de la optimización

Estos son los datos de mi blog antes y después:

Antes de optimizar:

  • Carga inicial: 6,2 s
  • Lighthouse rendimiento: 62 puntos
  • Peso total de imágenes: ~8 MB
  • LCP: 4,8 s
71%
Menos tiempo de carga
De 6,2 s a 1,8 s
62→95
Mejora en Lighthouse
Rendimiento +53 %
85%
Menos peso de imágenes
De 8 MB a 1,2 MB
1,8 s
Carga inicial
De 6,2 s a 1,8 s; Lighthouse de 62 a 95 puntos

Después de optimizar:

  • Carga inicial: 1,8 s (70 % más rápido)
  • Lighthouse rendimiento: 95 puntos (+53 %)
  • Peso total de imágenes: ~1,2 MB (85 % menos)
  • LCP: 1,3 s (73 % mejor)

Superó mis expectativas. Lo más importante: la tasa de rebote bajó unos 35 puntos y los usuarios se quedaban más tiempo.

Astro ya es un framework orientado al rendimiento; si las imágenes lo frenan, es una pena. Vamos a dejarlas bien configuradas.

Guía completa del componente Image de Astro

Astro incluye <Image /> y <Picture /> para optimizar imágenes. Al principio la documentación me confundió: ¿para qué sirven widths, quality e inferSize? Lo entendí probando en mi propio proyecto.

Uso básico: Image vs Picture

Empecemos con <Image />, el más habitual:

---
import { Image } from 'astro:assets';
import coverImage from '../assets/blog-cover.jpg';
---

<Image
  src={coverImage}
  alt="Portada del blog"
  width={1200}
  height={630}
/>

Este componente hace automáticamente:

  • Comprimir la imagen
  • Convertirla a WebP (comportamiento por defecto)
  • Generar imágenes responsivas
  • Optimizar el rendimiento de carga

<Picture /> es más potente y ofrece degradación entre formatos:

---
import { Picture } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---

<Picture
  src={heroImage}
  formats={['avif', 'webp', 'jpeg']}
  alt="Imagen hero"
  width={1920}
  height={1080}
/>

El navegador intenta AVIF primero (más ligero), luego WebP y, si no, JPEG. Rendimiento y compatibilidad a la vez.

Atributos clave explicados

Al principio no sabía cómo ajustarlos; tras varias pruebas, esto es lo que funciona:

widths — anchos responsivos

<Image
  src={image}
  widths={[400, 800, 1200]}
  sizes="(max-width: 768px) 400px, (max-width: 1024px) 800px, 1200px"
  alt="Imagen responsiva"
/>

Astro genera tres tamaños y el navegador elige según la pantalla: imagen pequeña en móvil, grande en escritorio. Menos datos y más velocidad.

quality — control de calidad

<Image
  src={image}
  quality="mid"  // o con número: quality={80}
  alt="Imagen del blog"
/>
  • low: miniaturas, fondos
  • mid: la mayoría de casos (recomendado)
  • high: cuando la calidad es crítica
  • Número (0-100): control preciso

Yo uso mid o 80: a simple vista no se nota y el archivo baja un 30-40 %.

inferSize — salvavidas para imágenes remotas

<Image
  src="https://example.com/image.jpg"
  inferSize={true}
  alt="Imagen remota"
/>

Si usas una URL remota sin conocer las dimensiones, inferSize las obtiene automáticamente. Me salvó más de una vez.

loading — configuración de lazy loading

<!-- Imagen del primer pantallazo, carga inmediata -->
<Image src={hero} loading="eager" alt="Imagen principal" />

<!-- Debajo del primer pantallazo, lazy loading -->
<Image src={content} loading="lazy" alt="Imagen de contenido" />

format — formato de salida

<Image
  src={image}
  format="webp"  // webp | avif | jpeg | png
  alt="Formato específico"
/>

Imágenes locales vs remotas

Esto también me costó al principio; en realidad es sencillo:

Imágenes locales (recomendado)

---
// En src/assets/ o src/images/
import myImage from '../assets/photo.jpg';
---
<Image src={myImage} alt="Imagen local" />

Astro las optimiza, comprime y empaqueta. Es la opción preferida.

Imágenes remotas

---
// Hay que autorizar el dominio en astro.config.mjs
---
<Image
  src="https://images.unsplash.com/photo-xxx"
  width={800}
  height={600}
  alt="Imagen remota"
/>

Configura en astro.config.mjs:

export default defineConfig({
  image: {
    domains: ['images.unsplash.com', 'cdn.example.com']
  }
});

Imágenes en public/

<!-- public/logo.png → /logo.png -->
<img src="/logo.png" alt="Logo" />

Ojo: lo que está en public/ no se optimiza. Solo para logos, favicons y archivos pequeños.

Ejemplos de código en producción

Esta es la configuración real de mi blog:

Portada del artículo (primer pantallazo, precarga)

---
import { Image } from 'astro:assets';
import coverImage from '../assets/blog-cover.jpg';
---

<Image
  src={coverImage}
  alt="Guía completa de optimización de imágenes en Astro"
  width={1200}
  height={630}
  format="webp"
  quality={85}
  loading="eager"
  class="blog-cover"
/>

Imágenes dentro del artículo (lazy loading)

<Image
  src={screenshot}
  alt="Captura de configuración"
  width={800}
  height={450}
  format="webp"
  quality="mid"
  loading="lazy"
/>

Avatar del autor (icono pequeño, precarga)

<Image
  src={avatar}
  alt="Avatar del autor"
  width={48}
  height={48}
  format="webp"
  loading="eager"
/>

Con el componente Image cubierto, veamos cómo elegir el formato: otro punto donde mucha gente duda.

Guía completa para elegir el formato de imagen

¿JPEG, PNG, WebP o AVIF? Al principio yo también me perdía. Tras probar cada uno, quedó claro cuándo usar cada formato.

Comparativa de los cuatro formatos principales

FormatoCompresiónTamañoSoporte en navegadoresCaso de uso
JPEGCon pérdidaMedio100 %Fotos, imágenes complejas
PNGSin pérdidaGrande100 %Transparencia
WebPCon/sin pérdidaPequeño97 %+Uso general (recomendado)
AVIFCon/sin pérdidaMínimo90 %+Máxima compresión

JPEG — formato clásico, máxima compatibilidad

  • Ventajas: todos los navegadores, compresión aceptable
  • Desventajas: sin transparencia, peor que WebP
  • Ideal para: ilustraciones de blog, fotos de producto, retratos

PNG — sin pérdida, con transparencia

  • Ventajas: calidad intacta, canal alpha
  • Desventajas: archivos grandes, a menudo 2-3 veces más que JPEG
  • Ideal para: logos, iconos, fondos transparentes

WebP — impulsado por Google, muy equilibrado

  • Ventajas: ~30 % más ligero que JPEG, transparencia, buen soporte
  • Desventajas: navegadores muy antiguos (en 2025, casi irrelevante)
  • Ideal para: la mayoría de escenarios; mi opción por defecto

AVIF — el más nuevo y compacto

  • Ventajas: 20-30 % menos que WebP con buena calidad
  • Desventajas: soporte algo menor, codificación más lenta
  • Ideal para: cuando el rendimiento es crítico

Árbol de decisión para elegir formato

¿No quieres leer tantos detalles? Sigue este flujo:

¿Necesitas transparencia?
├─ Sí → WebP (primera opción) o PNG (respaldo)
└─ No → continúa

¿Es una foto o imagen compleja?
├─ Sí → WebP (primera opción) o AVIF (máxima compresión)
└─ No → continúa

¿Es un logo o icono?
├─ Sí → SVG (vectorial)
└─ No → continúa

¿Es una animación?
└─ WebP (sustituto de GIF)

Mi regla práctica: en el 90 % de los casos, WebP basta. Buen soporte, buena compresión, sin complicaciones.

Compatibilidad entre formatos

Si quieres AVIF pero te preocupa la compatibilidad, usa <Picture> con degradación:

---
import { Picture } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---

<Picture
  src={heroImage}
  formats={['avif', 'webp', 'jpeg']}
  alt="Imagen hero"
  width={1920}
  height={1080}
/>

Orden de carga del navegador:

  1. Intenta AVIF (más ligero, más moderno)
  2. Si no, WebP (buen equilibrio)
  3. Si no, JPEG (máxima compatibilidad)

Los navegadores modernos obtienen lo mejor; los antiguos no se quedan sin imagen.

Prueba real de compresión

Probé con una imagen original de 2,5 MB:

FormatoTamañoCompresiónCalidad visual
Original (PNG)2,5 MB-Original
JPEG (quality=85)450 KB82 %Casi imperceptible
WebP (quality=85)180 KB93 %Casi imperceptible
AVIF (quality=85)120 KB95 %Casi imperceptible

Misma calidad percibida: WebP un 60 % más ligero que JPEG; AVIF un 73 % más.

Mis recomendaciones:

  • Uso diario: WebP
  • Máximo rendimiento: AVIF + WebP + JPEG en cascada
  • Transparencia: WebP primero, PNG como respaldo
  • Logos e iconos: SVG siempre que puedas (escala sin pérdida)

Con el formato claro, pasemos al lazy loading: bien configurado, acelera mucho el primer pantallazo.

Buenas prácticas de lazy loading

Lazy loading significa «cargar cuando haga falta»: las imágenes fuera del viewport no se descargan hasta que el usuario se acerca. Eso reduce mucho el tiempo de carga inicial.

Cómo funciona el lazy loading

Los navegadores actuales lo soportan nativamente con el atributo loading:

<img src="image.jpg" loading="lazy" alt="Imagen con lazy loading" />

El componente Image de Astro lo activa por defecto. Para control fino:

<!-- Lazy loading (por defecto) -->
<Image src={image} loading="lazy" alt="Lazy loading" />

<!-- Carga inmediata -->
<Image src={image} loading="eager" alt="Carga inmediata" />

El navegador usa Intersection Observer: cuando la imagen está a punto de entrar en pantalla, empieza la descarga.

Estrategia de configuración

La pregunta clave: ¿qué imágenes van con lazy loading y cuáles no?

Carga inmediata (loading=“eager”):

  • Imágenes visibles en el primer pantallazo (hero, portada)
  • Logo e iconos de navegación
  • Imágenes críticas del negocio (producto principal, avatar)
  • Todo el contenido above the fold

Lazy loading (loading=“lazy”):

  • Imágenes debajo del primer pantallazo
  • Ilustraciones y capturas dentro del artículo
  • Miniaturas en listados
  • Imágenes del pie de página
  • Elementos decorativos

Mi regla: 1-2 imágenes con carga inmediata en el primer pantallazo; el resto, lazy. Rápido al inicio sin descargar todo de golpe.

Ejemplos de configuración en producción

Página de inicio del blog

---
import { Image } from 'astro:assets';
---

<!-- Portada hero, carga inmediata -->
<Image
  src={heroCover}
  loading="eager"
  alt="Portada de inicio del blog"
  width={1920}
  height={1080}
/>

<!-- Miniaturas del listado, lazy loading -->
{posts.map(post => (
  <Image
    src={post.thumbnail}
    loading="lazy"
    alt={post.title}
    width={400}
    height={225}
  />
))}

Página de artículo

<!-- Imagen superior del artículo, carga inmediata -->
<Image
  src={article.cover}
  loading="eager"
  alt={article.title}
  width={1200}
  height={630}
/>

<!-- Imágenes del cuerpo, todas con lazy loading -->
<Image
  src={screenshot1}
  loading="lazy"
  alt="Captura de ejemplo de código"
  width={800}
  height={450}
/>

<Image
  src={screenshot2}
  loading="lazy"
  alt="Comparativa de resultados"
  width={800}
  height={450}
/>

Galería de imágenes (caso especial)

<!-- Primeras imágenes, carga inmediata -->
{gallery.slice(0, 6).map(img => (
  <Image src={img} loading="eager" alt={img.alt} />
))}

<!-- Resto, lazy loading -->
{gallery.slice(6).map(img => (
  <Image src={img} loading="lazy" alt={img.alt} />
))}

Monitorización del rendimiento

¿Cómo comprobar que funciona? Con estas herramientas:

1. Lighthouse (Chrome DevTools)

F12 → pestaña Lighthouse → «Analyze page load»:

  • Puntuación Performance: idealmente por encima de 90
  • LCP: por debajo de 2,5 s
  • CLS: cercano a 0 (evitar saltos de layout)

Antes tenía 62 puntos y LCP de 4,8 s; después, 95 puntos y LCP de 1,3 s.

2. Panel de red de Chrome DevTools

F12 → Network → activa «Disable cache» → recarga:

  • Revisa el waterfall: ¿las imágenes cargan en orden lógico?
  • ¿Las del primer pantallazo tienen prioridad?
  • ¿Las lazy solo cargan al hacer scroll?

3. WebPageTest

Para ver el comportamiento en distintas regiones y dispositivos: WebPageTest.

Comparativa antes/después:

MétricaAntesDespuésMejora
Carga inicial6,2 s1,8 s71 %
LCP4,8 s1,3 s73 %
Peso de imágenes del primer pantallazo8 MB1,2 MB85 %
Puntuación Performance629553 %

La diferencia en experiencia de usuario es enorme.

Con el lazy loading listo, veamos cómo integrar un CDN para acelerar el acceso global.

Integración práctica de CDN para imágenes

Al principio dudé si merecía la pena un CDN: configuración compleja, coste… Al final, el plan gratuito de Cloudflare cubrió mis necesidades y la configuración fue sencilla.

Por qué necesitas un CDN

Un CDN (Content Delivery Network) cachea tus imágenes en nodos repartidos por el mundo; el usuario descarga desde el más cercano.

Ventajas del CDN:

  • Aceleración global: Pekín desde un nodo en China, Nueva York desde uno en EE. UU.
  • Menos carga en el servidor: las peticiones de imágenes van al CDN
  • Optimización automática: muchos CDN convierten formato y comprimen
  • Resiliencia: si un nodo falla, hay otros

Tras conectar Cloudflare CDN, la carga para usuarios internacionales mejoró unos 60 %.

Integración con Cloudflare Image Resizing

Cloudflare ofrece Image Resizing y encaja muy bien con Astro.

Paso 1: activar Cloudflare Image Resizing

Cloudflare Dashboard → tu dominio → Speed → Optimization → activa «Image Resizing»

El plan gratuito incluye 50 000 transformaciones al mes; para un blog personal basta.

Paso 2: configurar astro.config.mjs

import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'server', // o 'hybrid'
  adapter: cloudflare({
    imageService: 'cloudflare' // servicio de imágenes de Cloudflare
  }),
  image: {
    // Dominios autorizados (imágenes remotas)
    domains: ['images.unsplash.com', 'cdn.example.com']
  }
});

Paso 3: autorizar dominios (imágenes remotas)

Si las imágenes vienen de un CDN externo, añádelos en image.domains:

export default defineConfig({
  image: {
    domains: [
      'images.unsplash.com',
      'cdn.example.com',
      'res.cloudinary.com'
    ]
  }
});

Con esto, el componente Image de Astro usará el servicio de imágenes de Cloudflare.

Otras opciones de CDN

Además de Cloudflare:

Cloudinary

CDN especializado en imágenes con SDK para Astro:

npm install @cloudinary/url-gen
---
import { CldImage } from 'astro-cloudinary';
---

<CldImage
  src="sample"
  width={800}
  height={600}
  alt="Imagen en Cloudinary"
/>

Muy potente (transformaciones, filtros, marcas de agua). El plan gratuito es limitado.

Uploadcare

Otro CDN de imágenes con subida y procesamiento sencillos:

// astro.config.mjs
export default defineConfig({
  image: {
    service: {
      entrypoint: 'uploadcare-astro',
      config: {
        publicKey: 'your-public-key'
      }
    }
  }
});

Cloudflare R2

Si tienes muchísimas imágenes, R2 como almacenamiento de objetos:

// astro.config.mjs
export default defineConfig({
  build: {
    assetsPrefix: 'https://your-r2-domain.com'
  }
});

R2 no cobra por tráfico de salida, solo por almacenamiento. Muy rentable a escala.

Precauciones al configurar el CDN

Estos son los fallos que yo cometí:

1. En modo SSR hay que activar la optimización por dominio

Con SSR, activa Image Resizing en el Dashboard de Cloudflare para cada dominio.

2. Las imágenes remotas requieren dominios autorizados

Si no, verás:

Image's component src parameter is not allowed for this image.

Solución: añade el dominio en image.domains de astro.config.mjs.

3. El modo compile solo optimiza en build

adapter: cloudflare({
  imageService: 'compile' // solo en tiempo de build
})

Las imágenes se optimizan al empaquetar, no en runtime. Ideal para sitios estáticos.

4. Revisa los límites gratuitos

Servicio CDNCuota gratuitaCoste extra
Cloudflare Image Resizing50 000/mes5 $/50 000
Cloudinary25 credits/mesSegún uso
Uploadcare3 GB almacenamiento + 3 GB tráficoSegún uso
Cloudflare R210 GB almacenamiento0,015 $/GB/mes

Para un blog personal suele bastar el plan gratuito; en proyectos comerciales, vigila el coste.

Ejemplo de comparación de costes:

Mi blog: ~20 000 visitas al mes, ~100 000 peticiones de imagen:

  • Cloudflare: gratis (dentro de 50 000)
  • Cloudinary: de pago (desde 9 $/mes)
  • Uploadcare: de pago (desde 25 $/mes)

Elegí Cloudflare: económico y eficaz.

Con el CDN configurado, repasemos la resolución de problemas frecuentes.

Problemas frecuentes y resolución de fallos

Aquí van los tropiezos que yo tuve; ojalá te ahorren tiempo.

La imagen no se muestra

Problema: hueco en blanco o icono de imagen rota.

Causas y soluciones:

1. Ruta de import incorrecta

// ❌ Error: ruta relativa mal escrita
import image from './assets/photo.jpg';

// ✅ Correcto: revisa los niveles de carpeta
import image from '../assets/photo.jpg';

2. Imagen remota sin dominio autorizado

// astro.config.mjs
export default defineConfig({
  image: {
    domains: ['images.unsplash.com'] // no lo olvides
  }
});

El error suele ser:

Image's component src parameter is not allowed for this image.

3. Formato no soportado

Astro admite: JPG, JPEG, PNG, WEBP, AVIF, GIF, SVG

Para TIFF o BMP, convierte antes.

Imagen borrosa o de mala calidad

Problema: se ve pixelada o con pérdida evidente.

Soluciones:

1. Ajusta quality

<!-- Calidad demasiado baja -->
<Image src={img} quality="low" alt="Muy borrosa" />

<!-- Sube la calidad -->
<Image src={img} quality={85} alt="Mucho más nítida" />

2. Resolución original insuficiente

Si el original es 400×300 y lo muestras a 1200×900, se verá mal. Usa una fuente de mayor resolución.

3. Tamaños responsivos mal configurados

<!-- ❌ Tamaños demasiado pequeños -->
<Image
  src={img}
  widths={[200, 400]}
  sizes="(max-width: 1920px) 400px"
  alt="Borrosa en escritorio"
/>

<!-- ✅ Suficientes tamaños -->
<Image
  src={img}
  widths={[400, 800, 1200, 1920]}
  sizes="(max-width: 768px) 400px, (max-width: 1024px) 800px, 1200px"
  alt="Nítida en cualquier pantalla"
/>

Errores en el build

Problema: npm run build falla por algo relacionado con imágenes.

1. Fallo al instalar Sharp

Error:

Error: Could not load the "sharp" module

Solución:

# Borra node_modules y reinstala
rm -rf node_modules package-lock.json
npm install

# O reinstala sharp solo
npm uninstall sharp
npm install sharp

Si persiste, prueba una versión concreta:

npm install [email protected]

2. Memoria insuficiente

Error:

FATAL ERROR: Reached heap limit Allocation failed

Solución: aumenta el límite de memoria de Node.js

# package.json
{
  "scripts": {
    "build": "NODE_OPTIONS='--max-old-space-size=4096' astro build"
  }
}

3. Formato no soportado

HEIC o TIFF pueden fallar con Sharp. Convierte a JPG o PNG antes.

Problemas de imágenes en modo SSR

Problema: en local funciona, pero en Cloudflare Pages/Workers las imágenes no aparecen.

Soluciones:

1. Configura imageService correctamente

// astro.config.mjs
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'server',
  adapter: cloudflare({
    imageService: 'cloudflare' // configuración clave
  })
});

2. Revisa el modo output

export default defineConfig({
  output: 'server', // o 'hybrid'
  // output: 'static' no soporta imageService de Cloudflare
});

3. Rutas de imágenes locales en SSR

En SSR, las imágenes locales van en src/, no en public/:

---
// ✅ Correcto: src/assets/
import image from '../assets/photo.jpg';

// ❌ Incorrecto: public/ no se optimiza
// <img src="/photo.jpg" />
---

<Image src={image} alt="Forma correcta" />

Lista de comprobación para depurar

Si algo falla, revisa en este orden:

  1. ✓ ¿La ruta de import es correcta?
  2. ✓ ¿El formato está soportado?
  3. ✓ ¿El dominio remoto está en la lista blanca?
  4. ✓ ¿El parámetro quality es razonable?
  5. ✓ ¿Sharp está instalado correctamente?
  6. ✓ ¿La configuración SSR es correcta?
  7. ✓ ¿Hay errores en la consola del navegador?
  8. ✓ ¿Qué estado tienen las peticiones de imagen en Network?

Conclusión

Dos días estudiando la optimización de imágenes en Astro; espero que esto te ahorre parte del camino.

Resumen de lo esencial:

  1. Componente Image: sustituye las etiquetas de imagen por <Image />; compresión, conversión de formato y responsividad automáticas
  2. Formato: WebP en el 90 % de los casos; AVIF con degradación si buscas el máximo; WebP o PNG si necesitas transparencia
  3. Lazy loading: 1-2 imágenes con carga inmediata en el primer pantallazo; el resto con lazy loading (hasta 50 % menos de carga inicial)
  4. CDN: Cloudflare con cuota gratuita suficiente; ~60 % más rápido para visitantes internacionales
  5. Depuración: sigue la lista; el 90 % de los problemas son rutas, configuración o Sharp

Tras optimizar, mi blog pasó de 6,2 s a 1,8 s de carga inicial, Lighthouse de 62 a 95 y rebote un 35 % menor. Muy buena relación esfuerzo/resultado.

Te sugiero hacer esto ahora:

  • Abre tu sitio, F12, ejecuta Lighthouse y mira tu puntuación actual
  • Revisa formatos: todo lo que pueda ir a WebP, que vaya
  • Añade loading="lazy" a las imágenes fuera del primer pantallazo
  • Si tienes muchas imágenes, valora Cloudflare CDN

La optimización de imágenes es un proceso continuo; no hace falta hacerlo todo de una vez. Cada mejora suma rendimiento y mejor experiencia.

Si tras optimizar te queda alguna duda o tienes trucos que compartir, déjalos en los comentarios. ¡Que tu sitio vuele!

Guía completa de optimización de imágenes en Astro: acelera tu sitio un 50%

5 técnicas prácticas para bajar la carga inicial de 6 s a 1,8 s y subir Lighthouse de 62 a 95 puntos

⏱️ Estimated time: 2 hr

  1. 1

    Step 1: Entender la importancia de optimizar imágenes y los objetivos

    Importancia de optimizar imágenes:
    • Suelen representar el 60-70 % del peso de una página y son el principal freno del rendimiento
    • En mi blog anterior, una portada sin comprimir pesaba 2,5 MB
    • Con unas capturas más, la página superaba fácilmente 5-6 MB
    • Solo esperar las imágenes llevaba varios segundos y la tasa de rebote era alarmante

    Requisitos de Google:
    • En Core Web Vitals, el LCP (Largest Contentful Paint) mide el pintado del contenido principal
    • Es el tiempo hasta que el contenido principal termina de cargar
    • Google exige un LCP por debajo de 2,5 s; por encima de 4 s es deficiente
    • En la mayoría de sitios, el LCP lo marca la portada o la imagen del primer pantallazo
    • Imágenes lentas = LCP alto = peor posicionamiento SEO

    Objetivos de optimización:
    • Carga inicial de 6,2 s a 1,8 s (71 % más rápido)
    • Lighthouse de 62 a 95 puntos (+53 %)
    • Peso total de imágenes de ~8 MB a ~1,2 MB (85 % menos)
    • LCP de 4,8 s a 1,2 s (75 % mejor)
  2. 2

    Step 2: Técnica 1: usar el componente Image de Astro

    Ventajas del componente Image de Astro:
    • Optimiza formato, tamaño y lazy loading automáticamente
    • Sustituye la etiqueta <img> por `<Image />`
    • Compresión, conversión de formato y tratamiento responsivo

    Pasos de configuración:
    1. Instala la integración @astrojs/image (npx astro add image)
    2. Configura imageService en astro.config.mjs (sharp o squoosh)
    3. Usa el componente Image:
    import { Image } from 'astro:assets';
    <Image src={image} alt="descripción" />

    Rutas de imágenes locales:
    • En modo SSR, las imágenes locales van en src/, no en public/
    • Correcto: import image from '../assets/photo.jpg'; <Image src={image} alt="forma correcta" />
    • Incorrecto: public/ no se optimiza
  3. 3

    Step 3: Técnicas 2-3: elegir formato y configurar lazy loading

    Elección de formato:
    • JPEG: fotos e imágenes complejas; máxima compatibilidad
    • PNG: iconos y fondos transparentes; archivos más grandes
    • WebP: 30-50 % más ligero que JPEG; buen soporte; WebP en el 90 % de los casos
    • AVIF: 20-30 % más ligero que WebP; formato más nuevo; compatibilidad algo menor; usa degradación si buscas el máximo

    Configurar lazy loading:
    • 1-2 imágenes con carga inmediata en el primer pantallazo; el resto con lazy loading
    • Puede reducir más del 50 % la carga inicial
    • Atributo loading="lazy" o la propiedad loading del componente Image
  4. 4

    Step 4: Técnicas 4-5: acelerar con CDN y optimizar dimensiones

    Integración con Cloudflare CDN:
    • Usa Cloudflare Images o almacenamiento R2
    • Configura optimización automática y conversión de formato
    • Más de 300 nodos globales; plan gratuito suficiente para blogs
    • En pruebas, la latencia bajó hasta 3 veces

    Pasos de configuración:
    1. Activa Images o R2 en Cloudflare Dashboard
    2. Configura imageService para usar Cloudflare
    3. Sube las imágenes a Cloudflare
    4. Carga las imágenes con la URL de Cloudflare

    Optimizar dimensiones:
    • Usa srcset y sizes para servir el tamaño adecuado por dispositivo
    • Define width y height en el componente Image para dimensiones coherentes
  5. 5

    Step 5: Depuración de fallos y buenas prácticas

    Lista de comprobación:
    1. Revisa si la ruta de import es correcta
    2. Comprueba si el formato está soportado
    3. Verifica si el dominio remoto está en la lista blanca
    4. Revisa si el parámetro quality es razonable
    5. Confirma que Sharp está instalado correctamente

    Problemas frecuentes:
    • Fallo al instalar Sharp → revisa la versión de Node; npm install sharp
    • Fallo al optimizar imagen remota → revisa la lista blanca de dominios
    • SSR no compatible → asegura output 'server' o 'hybrid'

    Buenas prácticas:
    • La optimización de imágenes es un proceso continuo; avanza paso a paso
    • Cada mejora suma rendimiento y mejor experiencia

    Haz esto ahora:
    1. Abre tu sitio, F12, ejecuta Lighthouse y mira tu puntuación
    2. Revisa formatos: todo lo que pueda ir a WebP, que vaya
    3. Añade loading="lazy" fuera del primer pantallazo
    4. Si tienes muchas imágenes, valora Cloudflare CDN

FAQ

¿Por qué es tan importante optimizar las imágenes?
Importancia de optimizar imágenes:
• Suelen representar el 60-70 % del peso de una página y son el principal freno del rendimiento
• En mi blog anterior, una portada sin comprimir pesaba 2,5 MB; con capturas, la página superaba 5-6 MB
• Solo esperar las imágenes llevaba varios segundos y la tasa de rebote era alarmante

Requisitos de Google:
• En Core Web Vitals, el LCP (Largest Contentful Paint) mide el pintado del contenido principal
• Es el tiempo hasta que el contenido principal termina de cargar
• Google exige un LCP por debajo de 2,5 s; por encima de 4 s es deficiente
• En la mayoría de sitios, el LCP lo marca la portada o la imagen del primer pantallazo
• Imágenes lentas = LCP alto = peor posicionamiento SEO
¿Qué resultados da la optimización de imágenes en Astro?
Resultados de la optimización:
• Carga inicial de 6,2 s a 1,8 s (71 % más rápido)
• Lighthouse de 62 a 95 puntos (+53 %)
• Peso total de imágenes de ~8 MB a ~1,2 MB (85 % menos)
• LCP de 4,8 s a 1,2 s (75 % mejor)

Tras optimizar mi blog, la carga bajó de 6,2 s a 1,8 s, Lighthouse pasó de 62 a 95 y la tasa de rebote bajó un 35 %. Muy buena relación esfuerzo/resultado.
¿Cómo usar el componente Image de Astro?
Ventajas del componente Image de Astro:
• Optimiza formato, tamaño y lazy loading automáticamente
• Sustituye la etiqueta <img> por `<Image />`
• Compresión, conversión de formato y tratamiento responsivo

Pasos de configuración:
1) Instala @astrojs/image (npx astro add image)
2) Configura imageService en astro.config.mjs (sharp o squoosh)
3) Usa el componente: import { Image } from 'astro:assets'; <Image src={image} alt="descripción" />

Rutas de imágenes locales:
• En modo SSR, las imágenes locales van en src/, no en public/
• Correcto: import image from '../assets/photo.jpg'; <Image src={image} alt="forma correcta" />
• Incorrecto: public/ no se optimiza
¿Cómo elegir el formato? ¿Qué diferencia hay entre JPEG, PNG, WebP y AVIF?
Elección de formato:
• JPEG (fotos e imágenes complejas; máxima compatibilidad)
• PNG (iconos y fondos transparentes; archivos más grandes)
• WebP (30-50 % más ligero que JPEG; buen soporte; WebP en el 90 % de los casos)
• AVIF (20-30 % más ligero que WebP; formato más nuevo; compatibilidad algo menor; usa degradación si buscas el máximo)

Mis recomendaciones:
• WebP en el 90 % de los casos
• AVIF con degradación si buscas el máximo rendimiento
• WebP o PNG si necesitas transparencia
¿Cómo configurar lazy loading y acelerar con CDN?
Configurar lazy loading:
• 1-2 imágenes con carga inmediata en el primer pantallazo; el resto con lazy loading
• Puede reducir más del 50 % la carga inicial
• Atributo loading="lazy" o la propiedad loading del componente Image

Integración con Cloudflare CDN:
• Usa Cloudflare Images o almacenamiento R2
• Configura optimización automática y conversión de formato
• Más de 300 nodos globales; plan gratuito suficiente para blogs
• En pruebas, la latencia bajó hasta 3 veces

Pasos de configuración:
1) Activa Images o R2 en Cloudflare Dashboard
2) Configura imageService para usar Cloudflare
3) Sube las imágenes a Cloudflare
4) Carga las imágenes con la URL de Cloudflare
¿Cómo depurar problemas de optimización de imágenes?
Lista de comprobación:
1) Revisa si la ruta de import es correcta
2) Comprueba si el formato está soportado
3) Verifica si el dominio remoto está en la lista blanca
4) Revisa si el parámetro quality es razonable
5) Confirma que Sharp está instalado correctamente

Problemas frecuentes:
• Fallo al instalar Sharp → revisa la versión de Node; npm install sharp
• Fallo al optimizar imagen remota → revisa la lista blanca de dominios
• SSR no compatible → asegura output 'server' o 'hybrid'

Sigue la lista paso a paso: el 90 % de los problemas son rutas, configuración o Sharp.

16 min de lectura · Publicado el: 3 dic 2025 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog