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

Por que as transições CSS causam layout shifts
Os Cumulative Layout Shifts causados por transições CSS ocorrem frequentemente no início da fase de carregamento da página. Esses layout shifts não acontecem de forma consistente, o que os torna difíceis de depurar.
Última revisão por Arjen Karel em março de 2026
Table of Contents!
O problema do transition: all
A causa mais comum de layout shifts relacionados a transições é o transition: all. De acordo com o capítulo de CSS do Web Almanac de 2022, 53% das páginas usam transition: all. Isso significa que toda alteração de propriedade é animada, incluindo aquelas que afetam o layout, como width, height, margin e padding.
Uma transição CSS possui uma property, duration, timing-function e um delay. A forma abreviada é 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 above-the-fold, como um menu de navegação, transita do seu estado inicial (sem estilo) para o seu estado final (com estilo ou até mesmo oculto). Se a propriedade de transição for all, isso inclui width, height e até visibility. O resultado: um layout shift que só acontece durante o carregamento e é quase impossível de reproduzir 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 acionam a etapa de layout do navegador. De acordo com a pesquisa do Google, páginas que animam propriedades CSS que induzem layout têm 15% menos probabilidade de passar no CLS. Páginas que animam margin ou border-width apresentam um CLS ruim com 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, sem layout shift): transform, opacity, filter, clip-path
Propriedades seguras (apenas pintura, sem layout shift): background-color, color, box-shadow, outline
A principal percepção: transform e opacity são manipulados inteiramente pela thread do compositor do navegador. Eles nunca acionam o recálculo de layout, portanto, nunca contam para o CLS. Se você precisar mover um elemento, use transform: translate() em vez de top/left. Se você precisar redimensionar visualmente, use transform: scale() em vez de width/height.
Dê uma olhada no exemplo abaixo. Ele 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.
Encontre e corrija transições CSS
Para encontrar e corrigir todos os layout shifts causados por transições CSS, precisamos executar um teste rápido. Primeiro, encontramos todas as transições CSS na página. Depois, 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 CLS.
Dica de Core Web Vitals: Cumulative Layout Shifts que são causados por transições CSS ocorrem frequentemente no início da fase de carregamento da página. Esses layout shifts não acontecem de forma consistente, o que os torna difíceis de depurar. Desacelerar sua rede emulando um dispositivo móvel e desabilitando o cache tornará mais fácil encontrá-los!
Passo 1: Encontre 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 levar 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 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: Modifique transições CSS
O snippet JavaScript acima mostrará todas as transições, bem como fornecerá um código de exemplo de como desabilitar essas transições. Para fins de testes rápidos, sugiro que você siga 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, é necessário um pouco mais de cuidado. Remova cuidadosamente apenas as transition-properties desnecessárias com base em cada seletor. Por exemplo, mude #button{transition: all .2s} para #button{transition: background-color .2s}
Passo 3: Meça a mudança no layout shift
transition: all por propriedades específicas viram seu CLS melhorar em 40%, em média.
Melhores práticas de transição
- 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 acionam o layout. Use
transform: translate()para mover elementos,transform: scale()para redimensioná-los visualmente, eopacitypara esmaecê-los. Isso é o que o Google recomenda para animações de alta performance. - Defina dimensões explícitas em elementos animados: Se um elemento precisa transitar, certifique-se de que ele tenha width e height explícitos (ou um aspect ratio) antes e depois da transição. Isso previne que o conteúdo ao redor se desloque. 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 o elemento para a sua própria camada de compositor. Mas isso vem com compensações: cria um novo contexto de empilhamento, aumenta o uso de memória da GPU e estabelece um bloco de contenção para descendentes posicionados. Aplique-o dinamicamente com JavaScript logo antes da animação começar e remova-o quando a animação terminar. Não deixewill-changeem sua folha de estilo permanentemente.
Apesar de tudo isso, o Web Almanac de 2025 relata que 40% das páginas móveis ainda executam animações não compostas. A boa notícia: o 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.
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
