Layout Shift causado por transições CSS

Aprenda a encontrar e remover transições CSS que criam layout shifts

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-02-07

Layout Shift causado por transições CSS: Entendendo e mitigando o impacto

Cumulative Layout Shifts que são causados por transições CSS geralmente ocorrem cedo durante a fase de carregamento da página. Esses layout shifts não acontecem consistentemente, o que os torna difíceis de depurar.

Entendendo as transições CSS:

As transições CSS são uma ferramenta poderosa para animar a mudança de uma propriedade ao longo do tempo. Elas são comumente usadas para efeitos como desvanecimento (fading), deslizamento e redimensionamento de elementos em uma página da web. Os desenvolvedores podem definir efeitos de transição especificando a propriedade a ser transicionada, a duração da transição e a função de tempo (timing function) que rege a aceleração da transição.

Uma transição pode ter uma propriedade, duração, função de tempo (timing-function) e um atraso (delay). A forma abreviada de uma transição é assim:

/* propriedade | duração | timing-function | atraso */
transition: margin-right 4s ease-in-out 1s;

Layout Shifts: A consequência não intencional:

Layout shifts ocorrem quando elementos em uma página da web mudam de posição ou tamanho, fazendo com que outros elementos fluam novamente e o layout geral da página mude. Embora as transições CSS sejam projetadas para fornecer animações suaves, elas podem desencadear inadvertidamente layout shifts, levando a uma experiência de usuário chocante e perturbadora. As causas mais comuns de layout shifts durante transições CSS incluem mudanças nas dimensões, posição ou visibilidade dos elementos.

Cumulative Layout Shifts causados por transições CSS geralmente ocorrem quando um elemento acima da dobra (above-the-fold), como um menu de navegação, transiciona do seu primeiro estado (sem estilo) para o seu estado final (estilizado ou até oculto). Isso geralmente é uma consequência não intencional de propriedades de transição excessivamente amplas. Por exemplo, uma entrada de menu deve transicionar apenas a cor de fundo e, em vez da propriedade de transição 'background-color', 'all' foi escolhido. Isso levará não apenas a uma transição de fundo, mas em alguns casos também a uma transição de largura, altura ou até visibilidade durante o carregamento da página.

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. Infelizmente, 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 fazer um teste rápido. Primeiro, precisamos encontrar todas as transições CSS. Depois de fazer isso, precisamos garantir que a transição não altere a posição (width, height, margin, padding, visibility) de um elemento. Podemos fazer isso modificando ou desativando essas transições. Por fim, podemos testar o impacto dessas alterações e decidir de uma vez por todas se as transições CSS estão causando problemas de CLS. 

Dica de Core Web Vitals: Cumulative Layout Shifts que são causados por transição CSS geralmente ocorrem cedo durante a fase de carregamento da página. Esses layout shifts não acontecem consistentemente, o que os torna difíceis de depurar. Desacelerar sua rede simulando um dispositivo móvel e desativando seu cache facilitará encontrá-los! 

Passo 1: Encontre transições CSS

Encontrar transições CSS pode ser feito manualmente: inspecione todas as folhas de estilo e pesquise a palavra 'transition'. Isso não deve dar mais de 10 minutos de trabalho, mas há uma maneira melhor! Basta colar este trecho (snippet) no console e pressionar enter

(() => {
 
  let nodeTable = [];
  let nodeArray = [];

  // Obter o nome do nó
  function getName(node) {
    const name = node.nodeName;
    return node.nodeType === 1
      ? name.toLowerCase()
      : name.toUpperCase().replace(/^#/, '');
  }

  // Obter o seletor
  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) {
      // Fazer nada...
    }
    return sel;
  };

  const getNodesWithTransition = (node) => {

    // Obter o estilo computado
    let cs = window.getComputedStyle(node);
    let tp = cs['transition-property'];
    let td = cs['transition-duration'];

    // Se houver uma transição, adicione-a à tabela
    if (tp !== '' && tp !== 'none' && td != '0s') {
      nodeTable.push({ selector: getSelector(node), transition: cs['transition'] });
      nodeArray.push(node);
    }

    // Chamar recursivamente esta função para cada nó filho
    for (let i = 0; i < node.children.length; i++) {
      getNodesWithTransition(node.children[i]);
    }
  }

  // encontrar todas as transições
  getNodesWithTransition(document.body);

  // Exibir os resultados no console
  console.log('%cTabela legível de seletores e suas transições', 'color: red; font-weight: bold;');
  console.table(nodeTable);

  console.log('%cNodeList para você inspecionar (mais difícil de ler, mas com mais informações)', 'color: red; font-weight: bold;');
  console.log(nodeArray);


  // estilos para substituir temporariamente as transições
  let selectors = nodeTable.map((item) => item.selector).join(', ');

  console.log('%cCSS específico para desativar todas as transições nesta página', 'color: red; font-weight: bold;');
  console.log(`<style>${selectors}{transition-property: none !important;}</style>`);
  
  console.log('%cCSS global para desativar todas as transições nesta página (não sugerido em produção)', 'color: red; font-weight: bold;');
  console.log(`<style>*{transition-property: none !important;}</style>`);

})()

Ele mostrará uma tabela com todas as transições, os elementos em que estão trabalhando e mais detalhes sobre as transições.

cls snippet table

Para encontrar layout shift, nós precisamos procurar por propriedades de transição como width,height, margin,paddingtransform, display e especialmente all (já que all inclui todas as propriedades de transição válidas)

Passo 2: Modifique transições CSS

O trecho de JavaScript acima mostrará todas as transições, bem como fornecerá um código de exemplo sobre como desativar essas transições. Para fins de testes rápidos, sugiro seguir o caminho mais fácil e desativar 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, um pouco mais de sutileza é necessária. Cuidadosamente, remova apenas as propriedades de transição desnecessárias com base no seletor. Por exemplo, altere #button{transition: all .2s} para  #button{transition: background-color .2s}

Passo 3: Meça a alteração no layout shift

O próximo e último passo é medir o impacto. Você pode usar minha extensão do Chrome Core Web Vitals Visualizer ou uma ferramenta RUM como o CoreDash para medir o impacto na vida real dessas alterações de código.

layout shift transition measured by coredash


Outras boas práticas de transição:

  1. Prefira Aceleração de GPU: Utilizar a aceleração de GPU para transições CSS pode descarregar a carga de trabalho de renderização da CPU para a GPU. Isso pode ser alcançado garantindo que as propriedades que estão sendo transicionadas sejam propícias à aceleração de GPU, como opacity e transform.
  2. Use a propriedade "will-change": A propriedade CSS will-change informa ao navegador que um elemento específico provavelmente será alterado, permitindo que ele otimize a renderização de acordo. 
  3. Garanta Dimensões Consistentes: Para evitar layout shifts causados por mudanças nas dimensões, certifique-se de que os elementos tenham dimensões consistentes antes e depois da transição. Isso pode envolver definir dimensões explícitas, usar valores baseados em porcentagem ou empregar técnicas como caixas de proporção (aspect ratio boxes).
  4. Otimize as Funções de Tempo (Timing Functions): A escolha da função de tempo pode impactar significativamente a percepção de suavidade durante uma transição. Esteja ciente dos padrões de aceleração e desaceleração e considere usar ease-in-out ou funções cubic bezier personalizadas para uma sensação mais natural.

Find out what is actually slow.

I map your critical rendering path using real field data. You get a clear answer on what blocks LCP, what causes INP spikes, and where layout shifts originate.

Book a Deep Dive
Layout Shift causado por transições CSSCore Web Vitals Layout Shift causado por transições CSS