Cumulative Layout Shift (CLS)

Milica Mihajlija
Milica Mihajlija
Philip Walton
Philip Walton

Navegadores compatibles

  • Chrome: 77
  • Edge: 79.
  • Firefox: No es compatible.
  • Safari: No se admite.

Origen

Los cambios de diseño inesperados pueden interrumpir la experiencia del usuario de muchas maneras, desde hacer que pierda el lugar mientras lee si el texto se mueve de repente hasta hacer que haga clic en el vínculo o botón incorrecto. En algunos casos, esto puede causar daños graves.

Un cambio repentino en el diseño hace que el usuario confirme un pedido grande que tiene la intención de cancelar.

El movimiento inesperado del contenido de la página suele ocurrir cuando los recursos se cargan de forma asíncrona o cuando los elementos DOM se agregan de forma dinámica a la página antes del contenido existente. La causa de los cambios de diseño puede ser imágenes o videos con dimensiones desconocidas, fuentes que se renderizan más grandes o más pequeñas que su resguardo inicial, o bien anuncios o widgets de terceros que cambian de tamaño de forma dinámica.

Las diferencias entre el funcionamiento de un sitio durante el desarrollo y la forma en que lo experimentan los usuarios empeoran este problema. Por ejemplo:

  • A menudo, el contenido personalizado o de terceros se comporta de forma diferente en el desarrollo y en la producción.
  • A menudo, las imágenes de prueba ya están en la caché del navegador del desarrollador, pero tardan más en cargarse para el usuario final.
  • Las llamadas a la API que se ejecutan de forma local suelen ser tan rápidas que los retrasos imperceptibles en el desarrollo pueden volverse sustanciales en la producción.

La métrica Desplazamiento del diseño acumulativo (CLS) te ayuda a abordar este problema midiendo la frecuencia con la que ocurre en los usuarios reales.

¿Qué es CLS?

El CLS es una medida del aumento de actividad más grande de las puntuaciones de cambio de diseño para cada cambio de diseño inesperado que ocurre durante todo el ciclo de vida de una página.

Un cambio de diseño ocurre cada vez que un elemento visible cambia su posición de un fotograma renderizado al siguiente. Más adelante en esta guía, se explica cómo se calculan las puntuaciones de cambios de diseño individuales.

Una ráfaga de cambios de diseño, conocida como ventana de sesión, ocurre cuando uno o más cambios de diseño individuales se producen en una sucesión rápida, con menos de 1 segundo entre cada cambio y un máximo de 5 segundos para la duración total de la ventana.

El aumento de actividad más grande es la ventana de sesión con la puntuación acumulativa máxima de todos los cambios de diseño dentro de esa ventana.

Ejemplo de ventanas de sesión. Las barras azules representan las puntuaciones de cada cambio de diseño individual.

¿Cuál es una buena puntuación de CLS?

Para proporcionar una buena experiencia del usuario, los sitios deben esforzarse por tener una puntuación de CLS de 0.1 o menos. Para asegurarte de alcanzar este objetivo para la mayoría de los usuarios, un buen umbral para medir es el percentil 75 de las cargas de páginas, segmentadas entre los dispositivos móviles y las computadoras de escritorio.

Los valores buenos de CLS son de 0.1 o menos, los valores deficientes son superiores a 0.25 y los valores intermedios deben mejorarse.
Los valores correctos de CLS son 0.1 o menos. Los valores deficientes son superiores a 0.25.

Para obtener más información sobre la investigación y la metodología que respaldan esta recomendación, consulta Definición de los umbrales de las métricas de las Métricas web esenciales.

El diseño cambia en detalle

Los cambios de diseño se definen en la API de Layout Instability, que informa entradas layout-shift cada vez que un elemento visible dentro del viewport cambia su posición inicial (por ejemplo, su posición superior y a la izquierda en el modo de escritura predeterminado) entre dos fotogramas. Estos elementos se consideran elementos inestables.

Ten en cuenta que los cambios de diseño solo se producen cuando los elementos existentes cambian su posición inicial. Si se agrega un elemento nuevo al DOM o un elemento existente cambia de tamaño, no se cuenta como un cambio de diseño, siempre y cuando el cambio no haga que otros elementos visibles cambien su posición inicial.

Puntuación de cambio de diseño

Para calcular la puntuación de cambio de diseño, el navegador observa el tamaño del viewport y el movimiento de los elementos inestables en el viewport entre dos fotogramas renderizados. La puntuación de cambio de diseño es el producto de dos medidas de ese movimiento: la fracción de impacto y la fracción de distancia (ambas se definen a continuación).

layout shift score = impact fraction * distance fraction

Fracción de impacto

La fracción de impacto mide el impacto de los elementos inestables en el área del viewport entre dos fotogramas.

La fracción del impacto de un fotograma determinado es una combinación de las áreas visibles de todos los elementos inestables de ese fotograma y el anterior, como una fracción del área total del viewport.

Ejemplo de fracción de impacto con un elemento inestable
Si un elemento cambia de posición, tanto su posición anterior como la actual contribuyen a su fracción de impacto.

En la imagen anterior, hay un elemento que ocupa la mitad de la ventana de visualización en un fotograma. Luego, en el siguiente fotograma, el elemento se desplaza hacia abajo un 25% de la altura de la ventana de visualización. El rectángulo rojo con puntos indica la unión del área visible del elemento en ambos fotogramas, que, en este caso, es el 75% del viewport total, por lo que su fracción de impacto es 0.75.

Fracción de distancia

La otra parte de la ecuación de la puntuación de cambio de diseño mide la distancia que se movieron los elementos inestables en relación con el viewport. La fracción de distancia es la distancia horizontal o vertical más alta que cualquier elemento inestable se movió en el marco dividida por la dimensión más grande del viewport (ancho o alto, la que sea mayor).

Ejemplo de fracción de distancia con un elemento inestable
La fracción de distancia mide qué tan lejos se movió un elemento del viewport.

En el ejemplo anterior, la dimensión más grande del viewport es la altura, y el elemento inestable se movió un 25% de la altura del viewport, lo que hace que la fracción de distancia sea 0.25.

Por lo tanto, en este ejemplo, la fracción de impacto es 0.75 y la fracción de distancia es 0.25, por lo que la puntuación de cambio de diseño es 0.75 * 0.25 = 0.1875.

Ejemplos

En el siguiente ejemplo, se ilustra cómo la adición de contenido a un elemento existente afecta la puntuación del cambio de diseño:

Ejemplo de cambio de diseño con varios elementos estables y _inestables_
Si agregas un botón a la parte inferior del cuadro gris, el cuadro verde se empuja hacia abajo y, en parte, fuera del viewport.

En este ejemplo, el cuadro gris cambia de tamaño, pero su posición inicial no cambia, por lo que no es un elemento inestable.

El botón "Haz clic en mí" no estaba en el DOM anteriormente, por lo que su posición inicial tampoco cambia.

Sin embargo, la posición inicial del cuadro verde sí cambia, pero como se movió parcialmente fuera del viewport, el área invisible no se considera cuando se calcula la fracción de impacto. La unión de las áreas visibles del cuadro verde en ambos fotogramas (ilustrada por el rectángulo rojo con puntos) es igual al área del cuadro verde en el primer fotograma: el 50% del viewport. La fracción de impacto es 0.5.

La fracción de distancia se ilustra con la flecha púrpura. El cuadro verde se movió hacia abajo alrededor del 14% de la ventana de visualización, por lo que la fracción de distancia es 0.14.

La puntuación de cambio de diseño es 0.5 x 0.14 = 0.07.

En el siguiente ejemplo, se muestra cómo varios elementos inestables afectan la puntuación del cambio de diseño de una página:

Ejemplo de cambio de diseño con elementos estables y _inestables_, y recorte del viewport
A medida que aparecen más nombres en esta lista ordenada, los nombres existentes se mueven para preservar el orden alfabético.

En el primer fotograma de la imagen anterior, hay cuatro resultados de una solicitud a la API para animales, ordenados alfabéticamente. En el segundo fotograma, se agregan más resultados a la lista ordenada.

El primer elemento de la lista ("Cat") no cambia su posición de inicio entre los fotogramas, por lo que es estable. Del mismo modo, los elementos nuevos que se agregaron a la lista no estaban en el DOM, por lo que sus posiciones iniciales tampoco cambian. Sin embargo, los elementos etiquetados como “Perro”, “Caballo” y “Zebra” cambian sus posiciones iniciales, lo que los convierte en elementos inestables.

Una vez más, los rectángulos rojos con puntos representan la unión de las áreas anteriores y posteriores de estos tres elementos inestables, que en este caso es alrededor del 60% del área del viewport (fracción de impacto de 0.60).

Las flechas representan las distancias que los elementos inestables se movieron desde sus posiciones iniciales. El elemento "Zebra", representado por la flecha azul, se movió más, alrededor de un 30% de la altura del viewport. Eso hace que la fracción de distancia en este ejemplo sea 0.3.

La puntuación de cambio de diseño es 0.60 x 0.3 = 0.18.

Cambios de diseño esperados frente a inesperados

No todos los cambios de diseño son negativos. De hecho, muchas aplicaciones web dinámicas cambian con frecuencia la posición inicial de los elementos de la página. Un cambio de diseño solo es malo si el usuario no lo espera.

Cambios de diseño iniciados por el usuario

Los cambios de diseño que se producen en respuesta a las interacciones del usuario (como hacer clic o presionar un vínculo, presionar un botón o escribir en un cuadro de búsqueda) suelen ser adecuados, siempre y cuando el cambio se produzca lo suficientemente cerca de la interacción para que la relación sea clara para el usuario.

Por ejemplo, si una interacción del usuario activa una solicitud de red que puede tardar un tiempo en completarse, lo mejor es crear espacio de inmediato y mostrar un indicador de carga para evitar un cambio de diseño desagradable cuando se complete la solicitud. Si el usuario no se da cuenta de que se está cargando algo o no tiene idea de cuándo estará listo el recurso, es posible que intente hacer clic en otra cosa mientras espera, lo que podría desaparecer.

Los cambios de diseño que se produzcan dentro de los 500 milisegundos desde la entrada del usuario tendrán establecida la marca hadRecentInput, por lo que se pueden excluir de los cálculos.

Animaciones y transiciones

Las animaciones y transiciones, cuando se hacen bien, son una excelente manera de actualizar el contenido de la página sin sorprender al usuario. El contenido que cambia de forma inesperada y abrupta en la página casi siempre crea una mala experiencia del usuario. Sin embargo, el contenido que se mueve de forma gradual y natural de una posición a la siguiente suele ayudar al usuario a comprender mejor lo que sucede y guiarlo entre los cambios de estado.

Asegúrate de respetar la configuración del navegador prefers-reduced-motion, ya que algunos visitantes del sitio pueden experimentar efectos negativos o problemas de atención con las animaciones.

La propiedad transform de CSS te permite animar elementos sin activar cambios de diseño:

  • En lugar de cambiar las propiedades height y width, usa transform: scale().
  • Para mover los elementos, evita cambiar las propiedades top, right, bottom o left, y usa transform: translate() en su lugar.

Cómo medir el CLS

El CLS se puede medir en el laboratorio o en el campo, y está disponible en las siguientes herramientas:

Herramientas de campo

Herramientas de lab

Mide los cambios de diseño en JavaScript

Para medir los cambios de diseño en JavaScript, usa la API de inestabilidad de diseño.

En el siguiente ejemplo, se muestra cómo crear un PerformanceObserver para registrar entradas de layout-shift en la consola:

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('Layout shift:', entry);
  }
}).observe({type: 'layout-shift', buffered: true});

Mide el CLS en JavaScript

Para medir el CLS en JavaScript, debes agrupar estas entradas layout-shift inesperadas en sesiones y calcular el valor máximo de la sesión. Puedes consultar el código fuente de la biblioteca de JavaScript web vitals, que contiene una implementación de referencia sobre cómo se calcula el CLS.

En la mayoría de los casos, el valor de CLS actual en el momento en que se descarga la página es el valor de CLS final de esa página, pero hay algunas excepciones importantes, como se indica en la siguiente sección. La biblioteca de JavaScript web vitals las considera tanto como sea posible, dentro de las limitaciones de las APIs web.

Diferencias entre la métrica y la API

  • Si una página se carga en segundo plano o se pone en segundo plano antes de que el navegador pinte cualquier contenido, no debería informar ningún valor de CLS.
  • Si se restablece una página desde la memoria caché atrás/adelante, su valor de CLS debe restablecerse a cero, ya que los usuarios experimentan esto como una visita a la página diferente.
  • La API no informa las entradas de layout-shift para los cambios que ocurren dentro de los iframes, pero la métrica sí, ya que forman parte de la experiencia del usuario de la página. Esto puede mostrarse como una diferencia entre CrUX y RUM. Para medir correctamente el CLS, debes considerarlos. Los submarcos pueden usar la API para informar sus entradas layout-shift al marco superior para la agregación.

Además de estas excepciones, CLS tiene cierta complejidad adicional debido a que mide la vida útil completa de una página:

  • Los usuarios pueden mantener una pestaña abierta durante un tiempo muy prolongado (días, semanas o meses). De hecho, es posible que un usuario nunca cierre una pestaña.
  • En los sistemas operativos para dispositivos móviles, los navegadores no suelen ejecutar devoluciones de llamada de descarga de páginas para las pestañas en segundo plano, lo que dificulta informar el valor "final".

Para controlar estos casos, se debe informar el CLS cada vez que una página está en segundo plano, además de cada vez que se descarga (el evento visibilitychange abarca ambas situaciones). Los sistemas de estadísticas que reciban estos datos deberán calcular el valor final de CLS en el backend.

En lugar de memorizar y lidiar con todos estos casos por tu cuenta, los desarrolladores pueden usar la biblioteca de JavaScript web-vitals para medir el CLS, que tiene en cuenta todo lo mencionado anteriormente, excepto el caso del iframe:

import {onCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);

Cómo mejorar el CLS

Si deseas obtener más orientación sobre cómo identificar cambios de diseño en el campo y usar datos de lab para optimizarlos, consulta nuestra guía sobre cómo optimizar CLS.

Recursos adicionales

Registro de cambios

En ocasiones, se descubren errores en las APIs que se usan para medir las métricas y, a veces, en las definiciones de las métricas. Como resultado, es necesario realizar cambios a veces, y estos pueden aparecer como mejoras o regresiones en tus informes y paneles internos.

Para ayudarte a administrar esto, todos los cambios en la implementación o definición de estas métricas se mostrarán en este registro de cambios.

Si tienes comentarios sobre estas métricas, puedes enviarlos al grupo de Google web-vitals-feedback.