Definición
CLS (siglas de Cumulative Layout Shift, o desplazamiento acumulativo del diseño) es una de las tres métricas de Core Web Vitals. Mide cuánto se mueven inesperadamente los elementos visuales de la página durante toda la carga.
Si estás leyendo un texto y de repente la página da un salto porque carga una imagen tarde, o un banner aparece de golpe empujando todo hacia abajo y te hace pinchar un botón equivocado — eso es CLS alto. Una de las experiencias más frustrantes que puede ofrecer una web.
El cálculo combina dos cosas:
- Impact fraction: cuánto del viewport afecta el movimiento
- Distance fraction: cuánto se mueven los elementos
Se va acumulando durante la sesión de carga (de ahí "cumulative") y reportando el peor escenario.
Umbrales de Google
| CLS | Calificación |
|---|---|
| ≤ 0.1 | Bueno ✅ |
| 0.1 – 0.25 | A mejorar ⚠️ |
| > 0.25 | Pobre ❌ |
Es una métrica adimensional (sin unidad). Para aprobar Core Web Vitals, el percentil 75 de tus visitantes debe estar ≤ 0.1.
Causas típicas de mal CLS
- Imágenes sin dimensiones declaradas: el navegador reserva 0px hasta que carga, luego "salta" al tamaño real
- Fuentes web cargadas tarde (FOIT/FOUT): el texto cambia de tamaño cuando llega la fuente
- Anuncios o iframes sin contenedor fijo: aparecen y empujan el contenido
- Banners de cookies tardíos que se inyectan después de cargar la página
- Carruseles, vídeos embebidos, widgets sin tamaño reservado
- Animaciones que cambian
width/heighten lugar detransform
Cómo evitarlo
1. Reserva siempre el espacio
Para imágenes, declara width y height (o usa CSS aspect-ratio):
<!-- Bien -->
<img src="hero.jpg" alt="..." width="1200" height="800">
<!-- O en CSS -->
<style>
.hero { aspect-ratio: 3 / 2; }
</style>
El navegador calcula el espacio antes de descargar la imagen.
2. Carga fuentes con font-display: optional o swap
@font-face {
font-family: 'MiFuente';
src: url('/fonts/mifuente.woff2') format('woff2');
font-display: swap; /* o 'optional' para CLS mínimo */
}
Mejor todavía: precargar fuentes críticas (<link rel="preload">).
3. Reserva espacios para anuncios y embeds
<div style="min-height: 250px;">
<!-- Adsense se inyectará aquí -->
</div>
4. Banner cookies al inicio, no al final
Renderiza el cookie banner antes que el contenido principal o pósicionalo en fixed para que no empuje nada.
5. Evita animar layout properties
/* Mal: cambia layout */
.btn:hover { padding: 20px; }
/* Bien: solo composite */
.btn:hover { transform: scale(1.05); }
Ejemplo práctico
Carga típica de una página con CLS alto:
0.0s ─ HTML carga, texto del artículo visible
0.8s ─ Fuente web carga, el texto cambia de tamaño ← CLS 0.04
1.5s ─ Imagen hero aparece (sin dimensiones, salta 400px) ← CLS 0.12
2.2s ─ Banner cookies aparece desde arriba, empuja todo ← CLS 0.08
3.5s ─ Anuncio de AdSense aparece a mitad del artículo ← CLS 0.06
CLS total = 0.30 ❌ Pobre
Tras optimizar:
0.0s ─ HTML + CSS con fuentes precargadas, texto correcto
0.6s ─ Imagen hero aparece en espacio reservado (no salta)
1.0s ─ Banner cookies aparece en posición fixed, no empuja
1.8s ─ Anuncio aparece en div con min-height reservado
CLS total = 0.02 ✅ Bueno
Errores comunes
- Atajos que ocultan el problema en Lighthouse pero lo dejan en producción: Lighthouse no detecta CLS tras interacciones (clic, scroll), solo durante carga inicial. CLS real puede ser peor.
- Asumir que CLS es solo de carga: las animaciones, transiciones y cambios reactivos del DOM tras carga también cuentan si el usuario no las inició.
- Cargar contenido AJAX sin reservar espacio: lazy-loading de comentarios, "leer más", filtros que añaden filas... todos pueden causar CLS si no reservas su altura inicial.
- Optimizar solo en desktop: en móvil con conexión 4G lenta, los efectos son más visibles. Mide siempre las dos vistas.
- No medir tras añadir un nuevo widget: cada vez que añades chat, cookie consent, ads o embed nuevo, vuelve a medir CLS.
Cuándo priorizar CLS
- Si Search Console te marca URLs en rojo en CLS — siempre primero, suele ser barato arreglarlo
- Tras un rediseño grande
- Tras añadir scripts de terceros (cookies, chat, ads)
- En cualquier página crítica de conversión (landing, checkout): el usuario que pincha en el botón equivocado por un salto = pérdida directa
Referencias
- web.dev — Optimize CLS
- web.dev — Cumulative Layout Shift
- PageSpeed Insights — mide tu CLS real