Lazy loading:
el secreto para que tu sitio cargue volando
(y por qué Google lo premia)
El lazy loading es, sin exagerar, la técnica más rentable que existe para acelerar un sitio web. No requiere reescribir la app, no necesita un servidor potente y, mejor aún, es completamente independiente del proveedor de imágenes que uses. Aquí explicamos por qué importa tanto y cómo implementarlo sin amarrarte a nadie.
1. Qué es el lazy loading (y por qué es tan importante)
Lazy loading —"carga perezosa" en español— es una técnica sencilla con un impacto enorme: en lugar de descargar todas las imágenes de una página al mismo tiempo cuando el usuario llega, el navegador descarga solo lo que está a punto de ser visible. El resto se descarga conforme el usuario hace scroll.
Piensa en una página típica: un hero con una foto de portada, tres secciones intermedias y una galería al final con doce imágenes. Sin lazy loading, el navegador pide las dieciséis imágenes antes de que el usuario haya visto siquiera la primera línea. Con lazy loading, descarga la del hero (la única visible) y deja el resto para después. El usuario empieza a ver tu página inmediatamente.
La regla del primer pantallazo
En la mayoría de los sitios, el usuario solo ve entre el 15% y el 30% del contenido total de una página. Si descargas únicamente lo que ve, en lugar de todo, estás bajando el peso inicial entre 3 y 6 veces sin tocar nada más.
Y lo mejor: el lazy loading es una técnica completamente del lado
del cliente. Vive en tu HTML y en una pequeña pieza de JavaScript (o incluso solo
en HTML moderno con loading="lazy").
No depende del backend, no depende del CDN y, sobre todo, no depende del proveedor de imágenes
que uses.
2. El impacto real en la velocidad de navegación
El número que importa al usuario es uno solo: cuánto tarda en ver y poder usar la página. El lazy loading mueve esa aguja de manera dramática porque ataca el problema más caro de toda página web: descargar bytes que el usuario nunca verá.
| Métrica | Sin lazy loading | Con lazy loading | Mejora típica |
|---|---|---|---|
| Peso inicial descargado | 8 – 12 MB | 1 – 2 MB | 5 – 8× menos |
| Tiempo hasta ver contenido (LCP) | 4 – 7 seg | 0.8 – 1.5 seg | 3 – 5× más rápido |
| Peticiones HTTP iniciales | 40 – 80 | 8 – 15 | 5× menos |
| Datos consumidos por usuario que no llega al footer | 100% del peso ⚠️ | solo lo visto | factura del CDN |
Hay un beneficio adicional que pocos mencionan: el lazy loading también te ahorra dinero. Si pagas por ancho de banda en tu CDN o por transformaciones en un proveedor de imágenes, no descargar lo que el usuario no verá significa menos facturación. Para un sitio con tráfico moderado, esto puede traducirse en cientos de dólares mensuales.
El multiplicador del scroll: en un blog largo o una landing extensa, los usuarios típicamente solo llegan al 40-60% del contenido. Eso significa que casi la mitad de las imágenes nunca son vistas. Sin lazy loading, las descargaste todas. Con lazy loading, solo entregaste lo que el usuario quiso ver.
3. Por qué Google lo recompensa en el ranking
Google no esconde sus criterios: desde 2021 los Core Web Vitals son señal oficial de ranking. Y dos de esas tres métricas se mejoran prácticamente solas cuando aplicas lazy loading correctamente.
LCP
Largest Contentful Paint
Al no competir con decenas de imágenes que el usuario ni va a ver, la imagen principal del hero llega al navegador antes. El LCP cae entre un 40% y un 70% en sitios bien implementados.
INP
Interaction to Next Paint
Menos imágenes en cola significa menos trabajo del navegador para decodificar y pintar. La página responde más rápido a clicks y taps mientras carga.
Crawl budget
Indexación de Google
Googlebot también es un visitante. Un sitio rápido permite que el bot indexe más páginas por sesión y vuelva más seguido. Resultado: tu contenido nuevo se indexa antes.
Google no se limita a recomendar lazy loading — lo trae incorporado
de fábrica en Chrome a través del atributo
loading="lazy". Cuando ves esa
directiva en una etiqueta <img>,
es exactamente lo que el equipo de Chrome quiere que hagas.
Dato clave: En PageSpeed Insights, una de las recomendaciones más frecuentes para mejorar el LCP es literalmente "Defer offscreen images" — diferir las imágenes fuera de pantalla. Eso es lazy loading. Si tu sitio marca rojo en esa categoría, lazy loading es la solución directa.
4. La independencia: por qué no debes amarrarte a un proveedor
Aquí viene la parte que pocos artículos abordan honestamente: el lazy loading es una técnica de cliente, no una funcionalidad de un proveedor. Vive en tu HTML y en tu JavaScript. Funciona perfectamente sin ningún proveedor externo.
Esto importa porque en producción real las cosas cambian: un día contratas un servicio de imágenes a la carta como Webability, Cloudinary o Imgix. Otro día decides cambiar de proveedor o llevarlo in-house. Si tu lazy loading está bien diseñado, ese cambio es cuestión de minutos y no toca tu HTML.
Las dos capas que conviene mantener separadas
Capa 1 — Lazy loading (tu código)
- Decide cuándo cargar una imagen
- Vive en tu HTML y un script propio
- Se basa en
IntersectionObserver - No conoce a tu proveedor
Capa 2 — Optimización (el proveedor)
- Decide qué versión entregar
- Vive en la URL de la imagen
- Resuelve formato, tamaño y compresión
- Es opcional y reemplazable
Si las dos capas se diseñan independientes, puedes activar/desactivar el proveedor con un solo cambio en la URL base. Si las mezclas (por ejemplo, dependiendo del SDK de un proveedor para detectar cuándo cargar), te amarras y cambiar duele.
En las siguientes secciones vamos a ver código concreto de las tres situaciones reales: primero un lazy loading que funciona solo, luego cómo conectarle un proveedor, y finalmente cómo desconectarlo cuando ya no lo necesitas — sin tocar el HTML.
5. Ejemplo: lazy load independiente (sin proveedor)
Empecemos por lo más limpio: un lazy loading que no depende de nadie. Tu sitio sirve sus propias imágenes y tú decides cuándo cargarlas.
El truco es siempre el mismo: no pongas la URL real en el atributo
src. Ponla en
data-src, y deja que un pequeño
script la mueva al src en el momento
adecuado.
El HTML
<!-- Imágenes con lazy load propio -->
<img class="lazy"
data-src="/images/foto-1.jpg"
width="800" height="600"
alt="Vista del producto">
<img class="lazy"
data-src="/images/foto-2.jpg"
width="800" height="600"
alt="Detalle del producto">
Nota cómo no hay src: solo
data-src. El navegador no
dispara la descarga automáticamente. Y los atributos
width y
height reservan el espacio
para evitar saltos visuales (CLS).
El script (sin librerías)
// lazy.js — versión independiente, ~20 líneas, sin dependencias
(function () {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
const img = entry.target;
// Mueve la URL real al src — el navegador descarga ahora.
img.src = img.dataset.src;
img.removeAttribute('data-src');
img.classList.remove('lazy');
img.classList.add('lazy-loaded');
observer.unobserve(img);
});
}, {
rootMargin: '200px 0px', // empieza a cargar 200px antes de ser visible
threshold: 0.01
});
document.querySelectorAll('img.lazy').forEach((img) => observer.observe(img));
})();
Eso es todo. Veinte líneas, cero dependencias, cero proveedores. Cualquier imagen con
clase lazy se carga solo
cuando entra (o está a punto de entrar) en pantalla. Y si el navegador no soporta
IntersectionObserver —caso
extremadamente raro hoy— la imagen simplemente nunca se carga, lo cual es
bastante seguro como degradación. Para una protección extra, puedes incluir un fallback
que cargue todo si el observer no existe.
Punto clave: el HTML solo conoce
/images/foto-1.jpg. No
sabe nada de proveedores, transformaciones ni formatos. Eso es lo que lo hace portátil.
6. Ejemplo: conectar el lazy load a un proveedor
Llega el día en que quieres entregar WebP a Chrome, AVIF a Safari, redimensionar al vuelo para cada dispositivo y servir desde un CDN global. Es decir: contratar un proveedor de imágenes a la carta.
Si tu HTML está bien diseñado, no tocas el HTML. Solo
cambias el script. El truco es que el script construya la URL del proveedor a partir del
data-src que ya tenías.
El HTML — exactamente igual que antes
<!-- Mismo HTML que en el ejemplo anterior. No cambia nada. -->
<img class="lazy"
data-src="/images/foto-1.jpg"
data-width="800"
width="800" height="600"
alt="Vista del producto">
Si quieres que el proveedor pueda redimensionar, agrega
data-width con el ancho real al
que se renderiza. Eso permite que el script pida la versión correcta para cada dispositivo.
El script — ahora con proveedor
// lazy.js — versión conectada a un proveedor (Webability como ejemplo)
(function () {
const PROVIDER = 'https://cdn.webability.info'; // base del proveedor
const ACCOUNT = 'mi-cuenta'; // tu identificador
const dpr = window.devicePixelRatio || 1; // soporte retina
// Función que transforma "/images/foto.jpg" en una URL del proveedor.
function buildUrl(originalSrc, width) {
const w = Math.round(width * dpr);
return `${PROVIDER}/${ACCOUNT}/w_${w},f_auto,q_auto${originalSrc}`;
}
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
const img = entry.target;
const original = img.dataset.src;
const width = parseInt(img.dataset.width || img.width || 800, 10);
// Aquí está la única línea que cambia respecto al ejemplo independiente:
img.src = buildUrl(original, width);
img.removeAttribute('data-src');
img.classList.remove('lazy');
img.classList.add('lazy-loaded');
observer.unobserve(img);
});
}, { rootMargin: '200px 0px', threshold: 0.01 });
document.querySelectorAll('img.lazy').forEach((img) => observer.observe(img));
})();
Una sola función nueva —buildUrl()—
y una línea modificada. El HTML sigue diciendo
/images/foto-1.jpg; el script
es el que decide convertir esa URL en
https://cdn.webability.info/mi-cuenta/w_800,f_auto,q_auto/images/foto-1.jpg
en el momento de la descarga. El navegador recibe AVIF si lo soporta, WebP si no, y el
tamaño exacto para la pantalla del usuario.
Lo importante: agregar el proveedor no rompió nada. Si mañana borras el script y vuelves al de la sección 5, las imágenes siguen funcionando — solo que sin transformación. Tu HTML está intacto.
7. Ejemplo: desconectar el proveedor sin romper nada
Imagina el escenario inverso: hace seis meses arrancaste con un proveedor, integraste todo, y ahora quieres cambiar de proveedor o servir tú mismo las imágenes. Si seguiste la receta de la sección anterior, esto es trivial.
Para "apagar" el proveedor, simplemente reemplaza lazy.js
con la versión independiente:
Cambiar a otro proveedor
// lazy.js — la nueva función buildUrl con otro proveedor.
// El resto del archivo es idéntico: el observer no cambia,
// el HTML no cambia, los data-src no cambian.
function buildUrl(originalSrc, width) {
// Antes: Webability
// return `https://cdn.webability.info/mi-cuenta/w_${width},f_auto,q_auto${originalSrc}`;
// Ahora: otro proveedor
return `https://otro-proveedor.cdn.com/fit-in/${width}x0/filters:format(auto)${originalSrc}`;
}
Apagar el proveedor por completo
// Para volver a servir desde tu propio dominio,
// simplemente devuelve la URL original sin tocarla.
function buildUrl(originalSrc, width) {
return originalSrc; // adiós proveedor.
}
Eso es todo. Una función que devuelve un string. El HTML del
sitio nunca se tocó: sigue teniendo
data-src="/images/foto.jpg"
como el primer día. Las miles de páginas, los miles de productos, los miles de artículos
siguen funcionando. La migración entre proveedores es un solo archivo JavaScript.
El patrón de oro
- El HTML guarda la URL "lógica" de la imagen
(por ejemplo,
/images/foto.jpg). - El JavaScript decide cuándo cargarla y cómo transformarla en una URL real.
- El proveedor es una decisión exclusiva del JavaScript. Cambiarlo, agregarlo o quitarlo nunca toca el HTML.
Cuando estas tres reglas se respetan, el lazy loading deja de ser una "feature de un proveedor" y se convierte en una capa propia, portátil y eterna de tu sitio.
8. Buenas prácticas y errores comunes
✓ Sí hacer
- Reservar espacio con
widthyheightpara evitar layout shifts (CLS). - Usar
rootMarginde 100-200px para empezar la carga antes de ser visible. - Excluir del lazy loading las imágenes above the fold (sobre todo el hero/LCP).
- Mantener
data-srccon la URL lógica, sin parámetros del proveedor.
✗ No hacer
- Aplicar lazy loading a la imagen del hero — empeora el LCP en lugar de mejorarlo.
- Hardcodear las URLs del proveedor en el HTML. Te amarras y cambiar duele.
- Olvidar el atributo
alt: SEO y accesibilidad sufren. - Cargar TODAS las imágenes a la vez con un solo trigger. Pierdes el beneficio.
Un detalle importante: la imagen del hero —la que carga primero
y define tu LCP— debería usar el atributo nativo
fetchpriority="high" en lugar
de lazy loading. Hacer lazy loading sobre el hero es contraproducente: es la única
imagen que el usuario sí ve inmediatamente.
Y para todo lo demás —galerías, sliders, contenido secundario, footers— el lazy loading es no negociable. Es la diferencia entre una página que aparece al instante y una que hace esperar.
9. Referencias y lecturas recomendadas
Las fuentes oficiales y técnicas más sólidas para profundizar en el tema:
Browser-level image lazy loading — web.dev (Google)
web.dev/articles/browser-level-image-lazy-loading
Guía oficial del equipo de Chrome sobre el atributo nativo
loading="lazy", cómo funciona internamente y
cuándo usarlo.
Intersection Observer API — MDN Web Docs (Mozilla)
developer.mozilla.org
Referencia técnica completa de la API en la que se basa el lazy loading moderno en JavaScript. Ejemplos, opciones de configuración y compatibilidad.
Largest Contentful Paint (LCP) — web.dev
web.dev/lcp
Cómo se mide el LCP, qué umbrales aplica Google y cómo el lazy loading correctamente implementado mejora la métrica.
Core Web Vitals — web.dev (Google)
web.dev/vitals
Las tres métricas oficiales de experiencia de usuario que afectan el ranking de Google: LCP, INP y CLS.
Google PageSpeed Insights
developers.google.com/speed/pagespeed/insights
Herramienta oficial de Google para auditar tu sitio. Si te dice "Defer offscreen images", significa que necesitas lazy loading.
Fetch Priority — web.dev (Google)
web.dev/articles/fetch-priority
Cómo combinar lazy loading con
fetchpriority="high" en la imagen del hero
para optimizar el LCP correctamente.
The Complete Guide To Image Optimization — Smashing Magazine
smashingmagazine.com
Análisis profundo y comparativa de proveedores de optimización de imágenes, CDNs y estrategias de lazy loading en producción.
Webability · Blog
Última actualización: 30 de abril de 2026