Cómo detectar y corregir problemas de Cumulative Layout Shift (CLS)

Aprende a detectar y corregir todos los problemas de Cumulative Layout Shift con datos de RUM, Chrome DevTools y fixes específicos de CSS y HTML.

Arjen Karel
Actualizado el · 12 min de lectura
Compartir

Cómo detectar y corregir problemas de Cumulative Layout Shift (CLS)

Esta página forma parte de nuestra serie sobre Cumulative Layout Shift (CLS). El CLS mide la estabilidad visual de la página registrando los movimientos inesperados de contenido. Una buena puntuación de CLS está por debajo de 0,1; por encima de 0,25 se considera mala. Si es tu primera vez con el CLS, empieza por la página central de CLS para conocer la fórmula, los umbrales y el funcionamiento de las session windows.

El CLS es la Core Web Vital con mejores resultados. Según el 2025 Web Almanac, el 72% de los sitios web supera el CLS a nivel global. Suena genial, hasta que te das cuenta de que la mayoría de los desarrolladores nunca ve problemas de CLS en su propia máquina. Los desplazamientos ocurren con visitantes primerizos en conexiones lentas. Para cuando lo compruebas en DevTools con la caché caliente, todo se ve bien. Justo eso hace que depurar el CLS sea tan complicado.

Esta guía se basa en el proceso paso a paso exacto que uso en mis consultorías de CLS. Primero datos de CrUX y RUM, validar en Chrome y luego escribir el fix.

Última revisión por Arjen Karel en marzo de 2026

CONSEJO SOBRE CLS: el CLS se mide en session windows, no como un total acumulado. El navegador agrupa los layout shifts en sesiones (máximo 5 segundos, con pausas de 1 segundo entre desplazamientos) y la puntuación de CLS corresponde a la peor sesión. Una sola ráfaga de desplazamientos al cargar la página puede hacer que suspendas el CLS, aunque el resto de la visita sea completamente estable.

Paso 1: comprueba el CLS en Search Console

Antes de cambiar nada, confirma que realmente tienes un problema de CLS. Entra en Google Search Console, ve a Core Web Vitals y revisa tanto móvil como desktop.

Si Google marca URLs con "CLS issue: more than 0.25" o "CLS issue: more than 0.1", tienes la confirmación del Chrome User Experience Report (CrUX) de que usuarios reales experimentan layout shifts en tu sitio.

A diferencia de LCP e INP, donde la potencia de cálculo y la velocidad de red son determinantes, los problemas de CLS pueden depender del dispositivo o del tamaño de pantalla. Cuando un mismo problema afecta a móvil y a desktop (imágenes sin dimensiones, font swaps, contenido inyectado), desktop puede registrar un valor de CLS mucho mayor debido al tamaño de la pantalla (porque puede verse afectada una porción mayor del viewport visible). Search Console agrupa las URLs: te dice qué tipos de página están afectados, pero no qué elementos se desplazan. Para eso necesitas Real User Monitoring.

Google Search Console showing INP issue: longer than 200ms (mobile) with 2.07M affected URLs

Paso 2: identifica problemas de CLS con datos de RUM

Search Console confirma que el problema existe, pero apenas da información para actuar. Necesitas saber qué elementos se desplazan, en qué páginas y en qué condiciones. Para eso necesitas una herramienta de RUM.

Creé CoreDash precisamente para responder a estas preguntas. Añades una sola etiqueta de script y empieza a recopilar datos de atribución de CLS de cada visitante real. El dato clave para depurar el CLS es el elemento que se desplaza: el nodo del DOM que realmente se movió. Sin esa información, estás depurando a ciegas.

Localiza los elementos que se desplazan

Empieza revisando los datos de CLS agrupados por elemento. En CoreDash, ve a la página de CLS y consulta la tabla ordenada por "CLS by Element". Esto muestra qué elementos provocan el mayor layout shift entre todos los visitantes. Haz clic en el peor de ellos para filtrar todas las métricas de las páginas donde se desplazó ese elemento.

CoreDash showing CLS scores broken down by shifting element.

Descubre qué páginas están afectadas

Tras filtrar por el elemento con mayor desplazamiento, revisa el desglose por URL. Los problemas de CLS pueden afectar a todo el sitio o solo a ciertas plantillas. Así sabrás si el CLS se concentra en tipos de página específicos: fichas de producto con galerías de imágenes, artículos de blog con bloques de anuncios o landing pages con animaciones en el hero. Saber qué páginas fallan te indica dónde poner el foco.

Compara visitantes nuevos con recurrentes

Esta es otra comprobación rápida que suelo hacer, y tiene más impacto de lo que la mayoría cree. El CLS por font swap solo ocurre cuando la fuente no está en caché. El CLS en imágenes provocado por width: auto solo ocurre cuando la imagen no está en la caché del navegador. Si el CLS es mucho peor en las primeras visitas, estás ante un desplazamiento dependiente de la caché. Como desarrollador, jamás lo verás en tu máquina a menos que desactives la caché (un consejo: desactiva siempre la caché de Chrome... pero esa es otra historia).

Comprueba los tipos de dispositivo y los tamaños de viewport

El CLS suele mostrar un patrón en móvil y desktop distinto al de LCP e INP. Los diseños responsive pueden introducir desplazamientos que solo aparecen con anchos y altos de viewport específicos. Un ad slot que da problemas en desktop tal vez ni siquiera esté en el viewport de móvil. Un menú de navegación puede animarse de forma distinta en breakpoints más pequeños. Agrupa los datos de CLS por tipo de dispositivo para saber dónde ocurren.

Paso 3: depura el CLS con Chrome

Los datos de RUM ya te han indicado qué elementos se desplazan y por qué. Ahora reproduce el problema en local y localiza la causa.

Usa la extensión Core Web Vitals Visualizer

La forma más rápida de ver los layout shifts es con la extensión de Chrome Core Web Vitals Visualizer. Carga la página, haz clic en el icono de la extensión y recarga. Cada layout shift se resalta con una capa de color que muestra con exactitud qué se movió y cuánto. Uso esto como primer paso antes de abrir el panel Performance, porque da una respuesta visual inmediata.

Core Web Vitals Visualizer showing layout shifts highlighted on the page.

Replica las condiciones en Chrome y revisa las capturas de red

Los problemas de CLS suelen ser invisibles con la caché caliente. Abre DevTools, desactiva la caché en la pestaña Network y limita la conexión a "Slow 4G" (mi opción favorita: te mostrará el CLS provocado por race conditions). Ahora haz clic en el icono del engranaje y desactiva la caché (mientras DevTools esté abierto). Esto simula las condiciones que experimentan quienes visitan la página por primera vez. Ve a la pestaña Network y activa las capturas de pantalla (screenshots). Ahora recarga la página y observa los desplazamientos.

Chrome DevTools Network tab with screenshots showing request timing for CLS analysis

Usa el panel Performance de Chrome

La mayoría de los layout shifts son fáciles de ver cuando sabes cómo buscarlos, pero a veces se resisten. Ese es el momento de abrir Chrome DevTools (Ctrl+Shift+I) e ir al panel Performance para analizarlos a fondo. Pulsa Ctrl+Shift+E para recargar y grabar. En cuanto cargue la página, haz scroll arriba y abajo varias veces. Detén la grabación.

Busca la pista "Layout Shifts". Cada desplazamiento aparece como un bloque de color. Haz clic en un desplazamiento para ver:

  • El nodo desplazado: el elemento del DOM que se movió
  • La puntuación del desplazamiento: fracción de impacto multiplicada por fracción de distancia
  • hadRecentInput: si hubo interacción del usuario antes del desplazamiento (los clics y toques tienen un margen de 500 ms, pero el scroll no)

Presta atención al momento en que ocurren los desplazamientos. Los desplazamientos durante la carga apuntan a imágenes sin dimensiones, font swaps o transiciones CSS. Los desplazamientos durante el scroll apuntan a animaciones activadas por scroll que usan propiedades de layout.

Chrome Performance panel showing layout shift entries during scrolling.

Prueba rápida: desactiva todas las transiciones

Las transiciones CSS que animan propiedades de layout son una causa traicionera de CLS: solo provocan desplazamientos durante la carga y cuesta reproducirlas. Pega este snippet en la consola, fuerza la recarga de la página con la caché desactivada y compara el CLS:

document.head.insertAdjacentHTML('beforeend',
  '<style>*{transition-property:none!important}</style>');

Si el CLS baja tras desactivar las transiciones, has dado con la causa. Consulta la guía para depurar transiciones CSS para localizar las transiciones concretas que lo provocan.

Cómo medir el CLS con la Layout Instability API

La Layout Instability API ofrece acceso directo a cada layout shift en JavaScript. Es la misma API que usan internamente las herramientas de RUM:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) {
      console.log('Layout shift:', {
        value: entry.value,
        sources: entry.sources?.map(s => ({
          node: s.node,
          previousRect: s.previousRect,
          currentRect: s.currentRect
        }))
      });
    }
  }
});
observer.observe({ type: 'layout-shift', buffered: true });

El array sources muestra qué elementos se movieron. hadRecentInput descarta los desplazamientos esperados tras clics y toques. Para medir esto en producción, utiliza CoreDash u otra herramienta de RUM.

Paso 4: corrige los problemas de CLS

Ya sabes qué elementos se mueven y por qué. Toca corregirlos. El CLS no tiene fases secuenciales como el LCP. En su lugar, los layout shifts se dividen en distintas categorías según su causa. Estas son las más habituales, en el orden en que suelo encontrarlas durante las auditorías.

1. Imágenes, vídeos e iframes sin dimensiones

Es la causa principal de CLS en la web. Según el 2025 Web Almanac, el 62% de las páginas en móvil incluye al menos una imagen sin dimensiones. La solución: incluye siempre los atributos width y height en las etiquetas <img>, <video> e <iframe>.

<img src="hero.jpg" width="800" height="450" alt="Description">

<style>
img {
    height: auto;
    max-width: 100%;
}
</style>

Cuidado con width: auto en el CSS. Esta sola declaración anula el cálculo de la relación de aspecto del navegador y provoca layout shifts aunque hayas definido width y height en el HTML. Lo he visto en decenas de sitios. Quien desarrolló la web hizo todo bien en el marcado, pero una regla global de CSS como img { width: auto; height: auto; max-width: 100%; } lo arruinó por completo. Para ver la explicación detallada, consulta cómo corregir el layout shift provocado por imágenes con auto-sizing. Si buscas una guía completa que cubre todas las causas de CLS relacionadas con imágenes y medios (vídeos, iframes, dirección de arte, imágenes responsive, lazy loading, placeholders), consulta cómo las imágenes y el contenido multimedia provocan layout shift.

2. Web font swaps

Cuando una fuente web carga y sustituye a la fuente fallback, la diferencia de tamaño genera un layout shift. El 2025 Web Almanac indica que solo el 11% de las páginas precarga fuentes web. Esto significa que la inmensa mayoría de los sitios es vulnerable al CLS por font swap.

La solución consta de dos partes. Primero, haz que la fuente fallback coincida con las dimensiones de la fuente web mediante metric overrides:

<style>
@font-face {
    font-family: 'My Font Fallback';
    src: local('Arial');
    size-adjust: 105.2%;
    ascent-override: 93%;
    descent-override: 24%;
    line-gap-override: 0%;
}

@font-face {
    font-family: 'My Font';
    src: url('/fonts/myfont.woff2') format('woff2');
    font-display: swap;
}

body {
    font-family: 'My Font', 'My Font Fallback', sans-serif;
}
</style>

Usa un Fallback Font Generator para calcular los valores de override correctos para tu combinación de fuentes. Segundo, acelera la entrega: aloja tú mismo las fuentes, precarga el archivo de fuente crítico y usa WOFF2 con subsetting. Para una estrategia completa, consulta carga responsive de fuentes web y cómo garantizar que el texto siga visible durante la carga de fuentes web.

3. Animaciones y transiciones CSS

Según el 2025 Web Almanac, el 40% de las páginas en móvil ejecuta animaciones non-composited. Estas animan propiedades como width, height, top, left, margin y padding, que provocan un recálculo de layout en cada fotograma.

El culpable más habitual es transition: all. Cuando se define transition: all .3s ease, cualquier cambio de propiedad se anima, incluidas las de layout. Durante la carga de la página, los elementos que pasan de su estado sin estilos al estilizado generan layout shifts intermitentes y casi imposibles de reproducir de forma consistente. Veo este patrón todo el tiempo.

La solución: sustituye las propiedades que provocan layout por propiedades composited.

  • Usa transform: translateY() en lugar de top/bottom
  • Usa transform: translateX() en lugar de left/right
  • Usa transform: scale() en lugar de width/height
  • Usa opacity en lugar de visibility combinada con cambios de altura
  • Nunca uses transition: all. Especifica la propiedad exacta: transition: background-color .2s ease

transform y opacity se ejecutan por completo en el compositor thread y nunca provocan layout. Para ver el proceso de depuración completo, consulta layout shift causado por transiciones CSS.

4. Anuncios, embeds y contenido inyectado dinámicamente

Los anuncios cargan tarde y empujan el contenido hacia abajo. Los banners de cookies aparecen y desplazan la página. Las peticiones AJAX inyectan contenido nuevo sin reservar espacio primero. Todos responden al mismo problema: aparece algo en la página que el navegador no conocía en el momento del render.

La solución para todos ellos es reservar espacio. Para los ad slots, define un min-height que coincida con el tamaño previsto del anuncio:

<style>
.ad-slot {
    min-height: 250px;
    contain: layout style;
}
@media (min-width: 600px) {
    .ad-slot { min-height: 90px; }
}
</style>

La declaración contain: layout style aísla el contenedor del anuncio del resto de la página. Para los banners de cookies, usa position: fixed para superponerlos en lugar de desplazar el contenido hacia abajo. Para el contenido AJAX, reserva espacio con min-height. No necesitas acertar al píxel: un descuadre de 50 px genera mucho menos CLS que un desplazamiento de 400 px por no haber reservado espacio.

Para embeds de terceros como YouTube, Google Maps y widgets de chat, aplica el patrón facade: muestra un placeholder estático y carga el embed real solo cuando el usuario interactúe con él. Cero CLS y cero recursos desperdiciados.

5. Layout shifts provocados por scroll

Esta es la causa de CLS que Lighthouse jamás detectará. Lighthouse no hace scroll en la página, de modo que los layout shifts provocados por scroll son totalmente invisibles en las pruebas de lab data. La única forma de encontrarlos es con datos de RUM o grabando una traza en el panel Performance mientras haces scroll manualmente.

El ejemplo más habitual es un encabezado hide-on-scroll que anima la propiedad top. Esto es lo que la mayoría de los desarrolladores no sabe: el scroll no se considera una interacción excluida en la especificación de Layout Instability. Los clics y toques tienen un margen de 500 ms. El scroll no. Todo layout shift provocado por el scroll cuenta para la puntuación de CLS.

La solución: usa transform: translateY() en lugar de top para cualquier animación asociada al scroll. Lo mismo se aplica a efectos parallax, barras de navegación que se comprimen y barras de progreso vinculadas al scroll. Si se mueve al hacer scroll, anímalo con transform. Para ver el tutorial completo con ejemplos en vídeo, consulta cómo las animaciones por scroll provocan CLS.

Checklist de soluciones rápidas

Causa del CLS Cómo detectarlo Solución
Imágenes/vídeos sin dimensiones Auditoría de «unsized images» en Lighthouse Añade width y height; elimina width: auto del CSS
Web font swaps RUM: el CLS solo empeora en la primera visita Font metric overrides; preload de WOFF2; alojar fuentes en tu servidor
Transiciones CSS Snippet de consola para listar todas las transiciones Sustituye transition: all por propiedades específicas; usa transform/opacity
Anuncios con carga tardía Atribución de RUM que muestra los contenedores del anuncio min-height en ad slots; contain: layout style
Banners de consentimiento de cookies Pico de CLS en la primera visita; banner en los datos de atribución Usa una capa superpuesta con position: fixed en vez de desplazar el contenido
Animaciones por scroll Traza de Performance durante el scroll; field CLS > lab CLS Sustituye top/left/height por transform

Guías relacionadas

Para obtener una visión completa de todas las Core Web Vitals, visita el hub de Core Web Vitals o usa la Ultimate Core Web Vitals Checklist para auditar todo tu sitio.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

Arjen Karel

¿Necesitas una web más rápida?

Soy Arjen y llevo 17 años arreglando webs lentas. Si te encuentras con problemas que no puedes resolver por tu cuenta, envíame tu URL y hablamos.

Envíame tu URL
Arjen Karel
Arjen Karel, Consultor de rendimiento web desde 2009

¿Por qué no funciona nuestro fix?

A veces la CDN sigue sirviendo el HTML antiguo, o el fix se metió en la plantilla de desktop y el móvil usa otra. Envíame tu URL y el problema, y te respondo con varias opciones. Primero reviso tus field data, luego dedicamos una hora a tu web, y en menos de un día tienes mis notas por escrito. 350 € sin IVA.

Envíame tu URL

¿No tienes desarrollador para hacer el fix? Hago el trabajo yo mismo, en una copia de tu web.