Layout Shift causado por transiciones CSS
Aprenda a encontrar y eliminar las transiciones CSS que crean layout shifts

Por qué las transiciones CSS causan layout shifts
Los Cumulative Layout Shifts causados por transiciones CSS a menudo ocurren temprano durante la fase de carga de la página. Estos layout shifts no ocurren de manera consistente, lo que los hace difíciles de depurar.
Última revisión por Arjen Karel en marzo de 2026
Table of Contents!
El problema de transition: all
La causa más común de los layout shifts relacionados con transiciones es transition: all. Según el capítulo de CSS del Web Almanac 2022, el 53% de las páginas utilizan transition: all. Eso significa que se anima cada cambio de propiedad, incluyendo las que afectan el diseño como width, height, margin y padding.
Una transición CSS tiene una propiedad (property), duración (duration), función de tiempo (timing-function) y un retraso (delay). La forma abreviada se ve así:
/* property | duration | timing-function | delay */ transition: margin-right 4s ease-in-out 1s;
El problema comienza cuando los desarrolladores escriben transition: all .3s ease en lugar de especificar la propiedad exacta que desean animar. Durante la carga de la página, un elemento "above-the-fold" como un menú de navegación hace una transición desde su estado inicial (sin estilos) hasta su estado final (con estilos o incluso oculto). Si la propiedad de transición es all, esto incluye width, height e incluso visibility. El resultado: un layout shift que solo sucede durante la carga y es casi imposible de reproducir de manera consistente.
¿Qué propiedades CSS causan layout shift?
No todas las transiciones CSS causan layout shifts. Solo las propiedades que cambian la geometría o la posición de un elemento activan el paso de diseño del navegador. Según la investigación de Google, las páginas que animan propiedades CSS que inducen layout shifts tienen un 15% menos de probabilidades de pasar el CLS. Las páginas que animan margin o border-width tienen un CLS deficiente a casi el doble de la tasa normal.
Propiedades que causan layout shift: width, height, margin, padding, top, left, right, bottom, border-width, font-size, display
Propiedades seguras (solo composición, sin layout shift): transform, opacity, filter, clip-path
Propiedades seguras (solo pintura, sin layout shift): background-color, color, box-shadow, outline
La clave: transform y opacity son manejados completamente por el hilo del compositor del navegador. Nunca activan el recálculo de diseño, por lo que nunca cuentan para el CLS. Si necesita mover un elemento, use transform: translate() en lugar de top/left. Si necesita cambiar el tamaño visualmente, use transform: scale() en lugar de width/height.
Eche un vistazo al ejemplo a continuación. Esto demuestra un layout shift causado por transiciones CSS que ocurren durante la fase de carga de una página. Veo este patrón todo el tiempo y encontrar y solucionar este tipo de problemas puede ser difícil.
Encontrar y solucionar transiciones CSS
Para encontrar y solucionar todos los layout shifts causados por transiciones CSS, necesitamos ejecutar una prueba rápida. Primero, encontramos todas las transiciones CSS en la página. Luego verificamos si alguna de ellas cambia propiedades que afecten el diseño. Finalmente, medimos el impacto de desactivar o modificar esas transiciones para confirmar que estaban causando CLS.
Consejo de Core Web Vitals: Los Cumulative Layout Shifts que son causados por transiciones CSS a menudo ocurren temprano durante la fase de carga de la página. Estos layout shifts no suceden de manera consistente, lo que los hace difíciles de depurar. ¡Ralentizar su red emulando un dispositivo móvil y desactivando su caché facilitará encontrarlos!
Paso 1: Encontrar transiciones CSS
La búsqueda de transiciones CSS se puede hacer manualmente: inspeccione todas las hojas de estilo y busque la palabra 'transition'. Eso no debería tomar más de 10 minutos de trabajo, ¡pero hay una manera mejor! Simplemente pegue este fragmento en la consola y presione enter
(() => {
let nodeTable = [];
let nodeArray = [];
// Get the name of the node
function getName(node) {
const name = node.nodeName;
return node.nodeType === 1
? name.toLowerCase()
: name.toUpperCase().replace(/^#/, '');
}
// Get the selector
const getSelector = (node) => {
let sel = '';
try {
while (node && node.nodeType !== 9) {
const el = node;
const part = el.id
? '#' + el.id
: getName(el) +
(el.classList &&
el.classList.value &&
el.classList.value.trim() &&
el.classList.value.trim().length
? '.' + el.classList.value.trim().replace(/\s+/g, '.')
: '');
if (sel.length + part.length > (100) - 1) return sel || part;
sel = sel ? part + '>' + sel : part;
if (el.id) break;
node = el.parentNode;
}
} catch (err) {
// Do nothing...
}
return sel;
};
const getNodesWithTransition = (node) => {
// Get the computed style
let cs = window.getComputedStyle(node);
let tp = cs['transition-property'];
let td = cs['transition-duration'];
// If there is a transition, add it to the table
if (tp !== '' && tp !== 'none' && td != '0s') {
nodeTable.push({ selector: getSelector(node), transition: cs['transition'] });
nodeArray.push(node);
}
// Recursively call this function for each child node
for (let i = 0; i < node.children.length; i++) {
getNodesWithTransition(node.children[i]);
}
}
// find all transitions
getNodesWithTransition(document.body);
// Display the results in the console
console.log('%cReadable table of selectors and their transitions', 'color: red; font-weight: bold;');
console.table(nodeTable);
console.log('%cNodeList for you to inspect (harder to read but more info)', 'color: red; font-weight: bold;');
console.log(nodeArray);
// styles to temporarity override the transitions
let selectors = nodeTable.map((item) => item.selector).join(', ');
console.log('%cSpecific CSS to disable all transitions on this page', 'color: red; font-weight: bold;');
console.log(`<style>${selectors}{transition-property: none !important;}</style>`);
console.log('%cGlobal CSS to disable all transitions on this page (not suggested on production)', 'color: red; font-weight: bold;');
console.log(`<style>*{transition-property: none !important;}</style>`);
})()
Le mostrará una tabla de todas las transiciones, los elementos en los que están trabajando y más detalles sobre las transiciones.

Para encontrar layout shifts, busque propiedades de transición como width, height, margin, padding, top, left, display y especialmente all (ya que all incluye todas las propiedades de transición válidas).
Paso 2: Modificar las transiciones CSS
El fragmento de JavaScript anterior mostrará todas las transiciones, así como código de ejemplo sobre cómo desactivar esas transiciones. Para fines de pruebas rápidas, le sugiero que tome el camino fácil y desactive todas las transiciones con una simple línea de código CSS
<style>*{transition-property: none !important;}</style>Por supuesto, para entornos en vivo se requiere un poco más de sutileza. Cuidadosamente elimine solo las propiedades de transición innecesarias por selector. Por ejemplo, cambie #button{transition: all .2s} a #button{transition: background-color .2s}
Paso 3: Medir el cambio en layout shift
transition: all con propiedades específicas vieron su CLS mejorar un 40% en promedio.
Mejores prácticas para transiciones
- Especifique siempre la propiedad exacta: Nunca use
transition: all. En su lugar, escribatransition: background-color .2s ease. Esto evita layout shifts accidentales de propiedades que no tenía la intención de animar. - Use transform y opacity para animaciones: Estas dos propiedades son manejadas por el compositor y nunca activan el diseño. Use
transform: translate()para mover elementos,transform: scale()para cambiar su tamaño visualmente yopacitypara desvanecerlos. Esto es lo que Google recomienda para animaciones de alto rendimiento. - Establezca dimensiones explícitas en los elementos animados: Si un elemento necesita hacer una transición, asegúrese de que tenga un width y height explícitos (o un aspecto ratio) antes y después de la transición. Esto evita que el contenido circundante se desplace. Para obtener más información sobre esto, consulte cómo solucionar layout shifts causados por imágenes de tamaño automático.
- Tenga cuidado con will-change: La propiedad CSS
will-changele dice al navegador que se prepare para una animación promoviendo el elemento a su propia capa de composición. Pero viene con compensaciones: crea un nuevo contexto de apilamiento, aumenta el uso de memoria de la GPU y establece un bloque de contención para los descendientes posicionados. Aplíquelo dinámicamente con JavaScript justo antes de que comience la animación y elimínelo cuando termine. No dejewill-changeen su hoja de estilos de forma permanente.
A pesar de todo esto, el Web Almanac 2025 informa que el 40% de las páginas móviles todavía ejecutan animaciones no compuestas. La buena noticia: el CLS es el Core Web Vital con la tasa de aprobación más alta, un 81% en dispositivos móviles. La mala noticia: si su sitio se encuentra en el 19% que falla, las transiciones CSS podrían ser la causa que aún no ha verificado.
Your Lighthouse score is not the full picture.
Your real users are on Android phones over 4G. I analyze what they actually experience.
Analyze field data
