La técnica de lazy loading (cargar recursos solo cuando son necesarios) es una de las formas más efectivas de mejorar la velocidad percibida y reducir el consumo de datos. Pero si se aplica sin criterio puede perjudicar tus Core Web Vitals, romper el SEO o impedir que usuarios vean contenido crítico. Aquí tienes una guía práctica y ordenada para aplicar lazy loading a imágenes y vídeos sin «cargar» problemas en tu web.
Qué es y cuándo usar lazy loading
Lazy loading pospone la descarga de recursos (imágenes, iframes, vídeos) hasta que están cerca de la ventana gráfica o el usuario los necesita. Es ideal para galerías largas, imágenes bajo el fold y iframes de terceros. No es buena idea para elementos que forman parte del contenido crítico visible al cargar la página (hero/LCP). Usa lazy loading para reducir bytes iniciales y mejorar tiempo de carga percibido.
Paso 1 — Prioriza lo crítico: no lances tu LCP
Antes de aplicar lazy loading identifica qué elemento es el LCP (Largest Contentful Paint). Nunca pongas loading="lazy"
en la imagen o vídeo que probablemente sea el LCP; eso retrasará su descarga y empeorará la métrica. Para elementos críticos usa fetchpriority="high"
o preloads adecuados y deja el lazy para el resto.
Paso 2 — Usa lazy nativo cuando baste
Hoy en día la forma más sencilla y robusta es confiar en el atributo nativo loading="lazy"
en <img>
y <iframe>
; los navegadores lo ignoran si no lo soportan, y evita dependencias externas. Ejemplo mínimo:
<img src="foto-800.jpg" alt="Descripción" loading="lazy" width="800" height="600">
<iframe src="https://player.example" loading="lazy" width="560" height="315"></iframe>
El lazy nativo es sencillo y eficiente para la mayoría de casos; úsalo siempre que no necesites un control más fino.
Paso 3 — Control fino con IntersectionObserver (mejor cobertura)
Para escenarios avanzados —placeholders LQIP, carga diferida de background-image
, o vídeos que deben arrancar solo cuando el usuario se acerca— utiliza IntersectionObserver
. Patrón habitual: deja en el src
una imagen de baja calidad o data-src
vacío y, al intersectar, sustituyes por la url real y remueves la observación. Ejemplo básico:
const imgs = document.querySelectorAll('img[data-src]');
if ('IntersectionObserver' in window) {
const io = new IntersectionObserver((entries, obs) => {
entries.forEach(e => {
if (e.isIntersecting) {
const img = e.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
obs.unobserve(img);
}
});
}, { rootMargin: '200px 0px' });
imgs.forEach(i => io.observe(i));
} else {
imgs.forEach(i => i.src = i.dataset.src);
}
Ajusta rootMargin
para cargar con antelación si quieres evitar demoras al hacer scroll rápido.
Paso 4 — Vídeos y embeds: poster, preload y carga on-demand
Para <video>
evita autoplay
y usa poster
para mostrar un placeholder; marca preload="metadata"
o none
y carga la fuente real con IntersectionObserver
o al click del usuario. Para embeds (YouTube/Vimeo) lo ideal es un placeholder con play que inyecta el <iframe>
cuando el usuario pulsa o cuando está muy cerca del viewport. Esto reduce solicitudes a terceros y evita impactos en memoria y Core Web Vitals.
Paso 5 — Responsive, dimensiones y evitar layout shifts
Para evitar Cumulative Layout Shift (CLS) siempre especifica width
y height
en las imágenes o usa aspect-ratio
CSS para reservar espacio. Emplea srcset
y sizes
para entregar imágenes adaptadas al dispositivo y así reducir bytes. Ejemplo:
<img src="img-800.jpg"
srcset="img-400.jpg 400w, img-800.jpg 800w, img-1200.jpg 1200w"
sizes="(max-width:600px) 100vw, 50vw"
width="1200" height="800"
loading="lazy" alt="...">
Paso 6 — Accesibilidad y SEO: alt + noscript + SSR
No sacrifiques accesibilidad: cada <img>
necesita alt
. Para SEO y bots considera un noscript
con la imagen final para que los rastreadores y usuarios sin JS vean el contenido. Si usas SSR, renderiza la imagen crítica server-side y lazy-load el resto.
Ejemplo de fallback:
<noscript><img src="imagen.jpg" alt="..."></noscript>
Paso 7 — Qué comprobar y herramientas
Mide el impacto con Lighthouse y los reportes de Core Web Vitals: compara LCP, CLS y First Contentful Paint antes/después. Revisa si tus cambios bloquean recursos críticos o si algún recurso lazy está retrasando interacciones. Usa DevTools Network y el informe de campo para validar.
Errores comunes que rompen la experiencia
- Lazy en hero/LCP (peor LCP). 2) No reservar espacio (CLS). 3) Depender solo de JS sin
noscript
. 4) Cargar iframes de terceros sin lazy o placeholder (impacto en memoria y TTFB). 5) Usarloading="lazy"
en todos los elementos sin distinguir prioridad. Evítalos priorizando y testeando.
Conclusión y checklist rápido
Prioriza: identifica tu LCP y no lo laces. Usa loading="lazy"
para la mayoría; recurre a IntersectionObserver
para casos avanzados. Pre-reserva espacio con width/height
o aspect-ratio
, usa srcset
/sizes
, añade poster
para vídeos y placeholder+click para embeds. Añade noscript
y alt
para accesibilidad y SEO. Mide con Lighthouse y field data: si el lazy mejora la experiencia, perfecto; si empeora LCP o genera CLS, reevalúa y ajusta prioridades.
¿Quieres que te genere ejemplos listos para copiar (HTML + CSS + JS) para: 1) galería de imágenes con LQIP, 2) vídeo lazy con poster, y 3) embed de YouTube on-demand?