Una imagen bien marcada no es solo <img src>: también comunica qué es para quien no puede verla, evita saltos de layout mientras carga, y se adapta a distintos tamaños de pantalla.
alt: obligatorio, y con criterio
alt describe la imagen para lectores de pantalla y aparece si la imagen no carga. Si la imagen es puramente decorativa, alt='' (vacío, pero presente) le dice al lector de pantalla que la ignore.
alt="Atardecer sobre la cordillera"
<!-- Imagen con contenido/información -->
<img src="/grafico-ventas.png" alt="Ventas subieron 24% en marzo" />
<!-- Imagen decorativa: alt vacío, no se omite el atributo -->
<img src="/textura-fondo.png" alt="" />
→Nunca escribas alt="imagen" o alt="foto de..." — describe el contenido o la función, no el hecho de que es una imagen.
→Si la imagen es un link o un botón, el alt debe describir el destino/acción, no la imagen en sí (ej: alt='Ir al carrito', no alt='ícono de carrito').
width, height y aspect-ratio: evitar Cumulative Layout Shift
Declarar width/height (o aspect-ratio) en la imagen le dice al navegador cuánto espacio reservar antes de que la imagen termine de cargar, evitando que el contenido de abajo 'salte'.
→object-cover recorta la imagen para llenar el contenedor sin deformarla; object-contain la encoge completa dejando posibles espacios vacíos.
figure + figcaption
figure agrupa contenido multimedia (imagen, gráfico, código) junto con su leyenda (figcaption). A diferencia de un <div>, comunica semánticamente que el bloque es una unidad autocontenida referenciable.
gráfico
Fig. 1 — Crecimiento de usuarios, 2024–2026.
<figure>
<img src="/grafico.png" alt="Crecimiento de usuarios 2024-2026" />
<figcaption>
Fig. 1 — Crecimiento de usuarios activos, 2024–2026.
</figcaption>
</figure>
→figcaption puede ir antes o después del contenido dentro de figure — el navegador y los lectores de pantalla lo asocian igual.
srcset y sizes: imágenes responsivas
srcset ofrece varias resoluciones de la misma imagen; sizes le indica al navegador qué tan ancha se va a mostrar según el viewport, para que elija la versión más liviana posible.
400w · 800w · 1200w → el navegador elige según pantalla
→El navegador decide sola qué imagen bajar según ancho de pantalla y densidad de píxeles (retina) — nunca hay que forzarlo con JS.
→En Astro, el componente <Image /> de astro:assets genera todo esto automáticamente a partir de una sola imagen fuente.
picture: art direction
picture permite servir una imagen recortada distinta según el viewport (no solo la misma imagen a otra resolución) — útil cuando el encuadre cuadrado de mobile no funciona igual en desktop panorámico.
mobile → hero-square.jpg desktop → hero-wide.jpg
<picture>
<source media="(min-width: 768px)" srcset="/hero-wide.jpg" />
<source media="(max-width: 767px)" srcset="/hero-square.jpg" />
<img src="/hero-wide.jpg" alt="Equipo trabajando en la oficina" />
</picture>
→El <img> final dentro de <picture> es obligatorio: es el fallback si ningún <source> aplica.
loading='lazy'
Difiere la carga de imágenes fuera de pantalla hasta que el usuario se acerca a ellas al hacer scroll, mejorando el tiempo de carga inicial.
→No lo uses en la imagen principal 'above the fold' (la primera que se ve sin hacer scroll) — ahí conviene loading='eager' (el default) o incluso fetchpriority='high'.