Layout Shift causado por transiciones CSS
Aprende cómo encontrar y eliminar 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 suceden de forma 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 de 2022, el 53% de las páginas utilizan transition: all. Eso significa que cada cambio de propiedad se anima, incluidas aquellas que afectan el diseño (layout) como width, height, margin y padding.
Una transición CSS tiene una propiedad (property), una duración (duration), una función de tiempo (timing-function) y un retraso (delay). La forma abreviada (shorthand) 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 quieren animar. Durante la carga de la página, un elemento por encima del pliegue (above-the-fold) como un menú de navegación hace una transición desde su estado inicial (sin estilo) a su estado final (estilizado o incluso oculto). Si la propiedad de transición es all, esto incluye la anchura (width), la altura (height) e incluso la visibilidad. El resultado: un layout shift que solo ocurre 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 (layout step) del navegador. Según la investigación de Google, las páginas que animan propiedades CSS que inducen el diseño tienen un 15% menos de probabilidades de pasar el CLS. Las páginas que animan margin o border-width tienen un mal CLS 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
El punto clave: transform y opacity son manejados completamente por el hilo del compositor del navegador. Nunca activan el recálculo del diseño, por lo que nunca cuentan para el CLS. Si necesitas mover un elemento, usa transform: translate() en lugar de top/left. Si necesitas cambiar el tamaño visualmente, usa transform: scale() en lugar de width/height.
Echa 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.
Encuentra y soluciona 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 afectan el diseño. Finalmente, medimos el impacto de deshabilitar o modificar esas transiciones para confirmar que estaban causando el 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 forma consistente, lo que los hace difíciles de depurar. ¡Ralentizar tu red emulando un dispositivo móvil y deshabilitando tu caché hará que sea más fácil encontrarlos!
Paso 1: Encuentra las transiciones CSS
Encontrar transiciones CSS se puede hacer manualmente: inspecciona todas las hojas de estilo y busca la palabra 'transition'. Eso no debería tomar más de 10 minutos de trabajo, ¡pero hay una manera mejor! Simplemente pega este snippet en la consola y presiona 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>`);
})()
Te 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, busca 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: Modifica las transiciones CSS
El snippet de JavaScript anterior mostrará todas las transiciones y también proporcionará un código de ejemplo sobre cómo deshabilitar esas transiciones. Para propósitos de pruebas rápidas, te sugiero que tomes el camino fácil y deshabilites todas las transiciones con una simple línea de código CSS
<style>*{transition-property: none !important;}</style>Por supuesto, para entornos en vivo (producción) se requiere un poco más de delicadeza. Elimina cuidadosamente solo las propiedades de transición innecesarias según cada selector. Por ejemplo, cambia #button{transition: all .2s} a #button{transition: background-color .2s}
Paso 3: Mide el cambio en el layout shift
transition: all con propiedades específicas vieron mejorar su CLS en un [CD:placeholder]% en promedio.
Mejores prácticas para las transiciones
- Especifica siempre la propiedad exacta: Nunca uses
transition: all. Escribetransition: background-color .2s easeen su lugar. Esto evita layout shifts accidentales de propiedades que no tenías la intención de animar. - Usa transform y opacity para las animaciones: Estas dos propiedades son manejadas por el compositor y nunca activan el diseño (layout). Usa
transform: translate()para mover elementos,transform: scale()para redimensionarlos visualmente yopacitypara atenuarlos. Esto es lo que Google recomienda para animaciones de alto rendimiento. - Establece dimensiones explícitas en los elementos animados: Si un elemento necesita hacer una transición, asegúrate de que tenga ancho y alto explícitos (o un aspect ratio) antes y después de la transición. Esto evita que el contenido circundante se desplace. Para más información sobre esto, consulta cómo solucionar los layout shifts causados por imágenes de tamaño automático.
- Ten 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 compositor. Pero viene con compensaciones (trade-offs): crea un nuevo contexto de apilamiento (stacking context), aumenta el uso de memoria de la GPU y establece un bloque de contención (containing block) para los descendientes posicionados. Aplícalo dinámicamente con JavaScript justo antes de que comience la animación, y elimínalo cuando termine la animación. No dejeswill-changeen tu hoja de estilo permanentemente.
A pesar de todo esto, el Web Almanac de 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 con un 81% en dispositivos móviles. La mala noticia: si tu sitio está en el 19% que falla, las transiciones CSS podrían ser la causa que aún no has verificado.
I have done this before at your scale.
Complex platforms, large dev teams, legacy code. I join your team as a specialist, run the performance track, and hand it back in a state you can maintain.
Discuss Your Situation
