Layout Shift causado por transições CSS
Aprenda como encontrar e remover transições CSS que criam layout shifts

Por que transições CSS causam layout shifts
Os Cumulative Layout Shifts causados por transições CSS ocorrem frequentemente no início, durante a fase de carregamento da página. Esses layout shifts não acontecem consistentemente, o que os torna difíceis de depurar.
Última revisão por Arjen Karel em março de 2026
Table of Contents!
O problema de transition: all
A causa mais comum de layout shifts relacionados a transições é transition: all. De acordo com o capítulo CSS do Web Almanac 2022, 53% das páginas usam transition: all. Isso significa que toda alteração de propriedade é animada, incluindo aquelas que afetam o layout (layout-affecting) como width, height, margin e padding.
Uma transição CSS tem uma propriedade (property), duração (duration), função de tempo (timing-function) e um atraso (delay). A abreviação (shorthand) é assim:
/* property | duration | timing-function | delay */ transition: margin-right 4s ease-in-out 1s;
O problema começa quando os desenvolvedores escrevem transition: all .3s ease em vez de especificar a propriedade exata que desejam animar. Durante o carregamento da página, um elemento acima da dobra (above-the-fold) como um menu de navegação transita do seu estado inicial (sem estilo) para o seu estado final (estilizado ou mesmo oculto). Se a propriedade de transição for all, isso inclui a largura (width), a altura (height) e até mesmo a visibilidade. O resultado: um layout shift que só acontece durante o carregamento e é quase impossível de ser reproduzido de forma consistente.
Quais propriedades CSS causam layout shift?
Nem todas as transições CSS causam layout shifts. Apenas as propriedades que alteram a geometria ou a posição de um elemento disparam a etapa de layout (layout step) do navegador. De acordo com a pesquisa do Google, as páginas que animam propriedades CSS que induzem ao layout têm 15% menos probabilidade de passar no CLS. Páginas que animam margin ou border-width têm CLS ruim em quase o dobro da taxa normal.
Propriedades que causam layout shift: width, height, margin, padding, top, left, right, bottom, border-width, font-size, display
Propriedades seguras (apenas composição (composite-only), sem layout shift): transform, opacity, filter, clip-path
Propriedades seguras (apenas pintura (paint-only), sem layout shift): background-color, color, box-shadow, outline
O insight chave: transform e opacity são tratados inteiramente pela thread do compositor do navegador. Eles nunca disparam o recálculo do layout, portanto nunca contam para o CLS. Se você precisar mover um elemento, use transform: translate() em vez de top/left. Se você precisa redimensionar visualmente, use transform: scale() em vez de width/height.
Dê uma olhada no exemplo abaixo. Isso demonstra um layout shift causado por transições CSS que ocorrem durante a fase de carregamento de uma página. Eu vejo esse padrão o tempo todo e encontrar e corrigir esses tipos de problemas pode ser difícil.
Encontrar e corrigir transições CSS
Para encontrar e corrigir todos os layout shifts causados por transições CSS, precisamos executar um teste rápido. Primeiro nós encontramos todas as transições CSS na página. Em seguida verificamos se alguma delas altera propriedades que afetam o layout. Por fim medimos o impacto de desabilitar ou modificar essas transições para confirmar se elas estavam causando o CLS.
Dica Core Web Vitals: Cumulative Layout Shifts que são causados por transições CSS frequentemente ocorrem cedo durante a fase de carregamento da página. Esses layout shifts não acontecem de forma consistente, o que os torna difíceis de depurar. Desacelerar a sua rede emulando um dispositivo móvel e desabilitando o seu cache tornará mais fácil encontrá-los!
Passo 1: Encontrar as transições CSS
Encontrar transições CSS pode ser feito manualmente: inspecione todas as folhas de estilo e pesquise pela palavra 'transition'. Isso não deve dar mais de 10 minutos de trabalho, mas existe uma maneira melhor! Basta colar este snippet no console e pressionar 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>`);
})()
Isso lhe mostrará uma tabela de todas as transições, os elementos em que elas estão trabalhando e mais detalhes sobre as transições.

Para encontrar layout shifts, procure por propriedades de transição como width, height, margin, padding, top, left, display e especialmente all (já que all inclui todas as propriedades de transição válidas).
Passo 2: Modificar transições CSS
O snippet de JavaScript acima mostrará todas as transições, além de fornecer um código de exemplo sobre como desabilitar essas transições. Para fins de testes rápidos eu sugiro que você pegue o caminho mais fácil e desabilite todas as transições com uma simples linha de código CSS
<style>*{transition-property: none !important;}</style>É claro que para ambientes de produção (live) é necessária um pouco mais de sutileza. Remova cuidadosamente apenas as propriedades de transição desnecessárias por seletor (per-selector basis). Por exemplo, mude #button{transition: all .2s} para #button{transition: background-color .2s}
Passo 3: Medir a mudança no layout shift
transition: all por propriedades específicas viram seu CLS melhorar em [CD:placeholder]% em média.
Melhores práticas para transições
- Sempre especifique a propriedade exata: Nunca use
transition: all. Escrevatransition: background-color .2s easeem vez disso. Isso previne layout shifts acidentais de propriedades que você não pretendia animar. - Use transform e opacity para animações: Essas duas propriedades são manipuladas pelo compositor e nunca disparam o layout. Use
transform: translate()para mover os elementos,transform: scale()para redimensioná-los visualmente, eopacitypara esmaecê-los (fade). Isso é o que o Google recomenda para animações de alta performance. - Defina as dimensões explícitas em elementos animados: Se um elemento precisa transitar, certifique-se de que ele tenha largura e altura explícitas (ou um aspect ratio) antes e depois da transição. Isso evita que o conteúdo ao redor mude. Para saber mais sobre isso, veja como corrigir layout shifts causados por imagens com dimensionamento automático.
- Tenha cuidado com o will-change: A propriedade CSS
will-changediz ao navegador para se preparar para uma animação promovendo l'elemento à sua própria camada (layer) de compositor. Mas isso vem com compensações (trade-offs): cria um novo contexto de empilhamento (stacking context), aumenta o uso de memória da GPU e estabelece um bloco de contenção (containing block) para descendentes posicionados. Aplique-o dinamicamente com JavaScript logo antes do início da animação e remova-o quando a animação terminar. Não deixe owill-changena sua folha de estilo de forma permanente.
Apesar de tudo isso, o Web Almanac 2025 relata que 40% das páginas mobile ainda executam animações não-compostas (non-composited). A boa notícia: CLS é o Core Web Vital com a maior taxa de aprovação com 81% em dispositivos móveis. A má notícia: se o seu site estiver nos 19% reprovados, as transições CSS podem ser a causa que você ainda não verificou.
Performance degrades unless you guard it.
I do not just fix the metrics. I set up the monitoring, the budgets, and the processes so your team keeps them green after I leave.
Start the Engagement
