Como as Animações Acionadas por Rolagem Causam CLS

Seu cabeçalho que se oculta na rolagem pode estar falhando silenciosamente no CLS. Veja o motivo e como corrigir isso.

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-26

Sempre que me pedem para fazer uma auditoria do Cumulative Layout Shift, obviamente começo com as mudanças durante a fase de carregamento. Eu verifico imagens sem dimensões, anúncios injetados, trocas de fontes (FOUT).

Mas nem todo CLS acontece durante o carregamento da página. Às vezes, ele é acionado por interações como a rolagem. Elas são difíceis de detectar porque o Lighthouse não faz a rolagem e você precisa saber exatamente onde procurar.

Última revisão por Arjen Karel em março de 2026

Em uma auditoria recente, adicionei dados RUM do CoreDash e notei um padrão suspeito. Um elemento #header parecia causar muito mais mudança de layout do que o normal.

coredash cls scroll header

Acontece que o que estamos vendo aqui é um cabeçalho fixo que se oculta quando o usuário rola para baixo e reaparece quando rola para cima. É um padrão que vejo com bastante frequência e, se não for feito corretamente, causará uma mudança de layout a cada mudança de direção da rolagem.

Por que as mudanças acionadas por rolagem são diferentes

Normalmente, o CLS não acontece após uma interação. O CLS mede mudanças de layout inesperadas e, após uma interação, é de se esperar que o layout mude. É por isso que a métrica CLS tem um período de tolerância automático de 500ms. As mudanças de layout que ocorrem dentro de 500 milissegundos após uma interação do usuário são excluídas da pontuação do CLS. O navegador lida com isso definindo e verificando uma flag hadRecentInput nessas mudanças.

O problema é que isso se aplica apenas a eventos discretos como cliques, toques e pressionamentos de teclas. De acordo com a especificação Layout Instability, a rolagem explicitamente não é uma entrada de exclusão. Nem arrastar ou gestos de pinça para aplicar zoom. Apenas eventos discretos recebem o período de tolerância de 500ms.

Isso significa que cada mudança de layout acionada por um evento de rolagem conta para a sua pontuação de CLS.

De acordo com o Web Almanac de 2025, 40% das páginas mobile ainda usam animações não compostas (non-composited). Estas são animações em propriedades como top, height ou margin que acionam a recalcular o layout a cada frame. Se qualquer uma delas for disparada durante uma rolagem, cada frame único conta para o seu CLS.

O problema do cabeçalho que se oculta na rolagem

Vamos começar com o problema que encontrei hoje, o 'problema do cabeçalho que se oculta na rolagem'. Um cabeçalho fixo usa JavaScript para alternar a visibilidade na rolagem. A implementação é assim:

/* CSS */
#header {
  position: fixed;
  top: 0;
  transition: top 0.3s ease;
}

/* JavaScript */
window.addEventListener('scroll', () => {
  if (scrollingDown) {
    header.style.top = '-80px';  // hide
  } else {
    header.style.top = '0px';    // show
  }
});

A mudança de layout é causada pela combinação de transition: top 0.3s ease e a alteração de header.style.top no JavaScript.

Eis o motivo: top é uma propriedade de layout. Quando o navegador processa uma alteração em top, ele executa o pipeline de renderização completo (rendering pipeline): Style, Layout, Paint, Composite. Em cada frame de animação durante essa transição, o navegador recalcula o layout. Cada recálculo produz uma nova entrada de mudança de layout.

A cada mudança de direção de rolagem, o contador do CLS continua subindo enquanto o usuário interagir com a página.

Construí uma demonstração reproduzindo exatamente esse comportamento de um site em produção que eu estava auditando e gravei um vídeo. O CLS total ultrapassou 0.1 após alguma rolagem. Convenhamos: esse nível de rolagem não acontece com frequência na vida real, mas a mecânica não muda. E já vi essa mudança de layout empurrar os sites para além do limite e fazer com que seu CLS total falhasse.

Quais propriedades CSS podem causar mudanças de layout quando animadas?

Para que uma animação cause CLS, ela precisa acionar o Layout. O pipeline de renderização do navegador tem três estágios principais após o cálculo de estilo: Layout, Paint e Composite. Propriedades que afetam apenas o estágio Composite nunca causam mudanças de layout. Para mais detalhes sobre como as transições CSS causam mudanças de layout, veja o artigo complementar.

Propriedades que acionam o layout (e causam CLS quando animadas):

top, left, right, bottom, width, height, margin, padding, border-width, font-size

Todas essas alteram a geometria ou a posição de um elemento. O navegador deve recalcular a posição do elemento (e possivelmente de outros elementos também).

Propriedades que ignoram totalmente o layout (e são seguras para animação):

transform e opacity são executados na thread do compositor. Eles ignoram tanto o layout quanto o paint. O navegador lida com eles na GPU (é por isso que essas animações funcionam mesmo enquanto a main thread está ocupada). Como eles nunca acionam o recálculo do layout, eles nunca produzem entradas de mudança de layout.

Substitua as propriedades de layout por transforms

A correção para o cabeçalho que se oculta na rolagem é simples. Substitua a animação de top por transform: translateY().

/* CSS - BEFORE (causes CLS) */
#header {
  position: fixed;
  top: 0;
  transition: top 0.3s ease;
}

/* CSS - AFTER (no CLS) */
#header {
  position: fixed;
  top: 0;
  transition: transform 0.3s ease;
}

/* JavaScript - BEFORE */
header.style.top = '-80px';

/* JavaScript - AFTER */
header.style.transform = 'translateY(-80px)';

Isso dá o mesmo resultado: o cabeçalho desliza para cima e desaparece. Mas transform: translateY() roda inteiramente no compositor e nunca causa uma mudança de layout.

O mesmo princípio se aplica a qualquer animação acionada por rolagem:

  • Painéis deslizantes: use transform: translateX() em vez de left ou right
  • Elementos em expansão: use transform: scaleY() em vez de height
  • Elementos com efeito de esmaecimento (fade): use opacity em vez de visibility combinado com alterações de height

Outros padrões acionados por rolagem que causam CLS

O cabeçalho que se oculta na rolagem é algo que vejo com bastante frequência, mas existem mais. Qualquer JavaScript que altere uma propriedade de layout em resposta a eventos de rolagem produzirá uma mudança de layout. Por exemplo:

Efeitos de Parallax usando top ou margin-top. Substitua por transform: translateY() ou use a abordagem CSS perspective e translateZ para parallax em CSS puro.

Navegação pegajosa (sticky) que muda de height na rolagem. Uma barra de navegação que encolhe de 80px para 50px quando o usuário rola além de um limite. Se a mudança de height for animada com transition: height, substitua-a por transform: scaleY().

Barras de progresso vinculadas à rolagem usando width. Um indicador de progresso de leitura que cresce da esquerda para a direita animando o width. Em vez disso, use transform: scaleX() com transform-origin: left.

Alternativa moderna: CSS Scroll-Driven Animations. A API animation-timeline: scroll() permite conduzir animações a partir do progresso da rolagem sem qualquer JavaScript. Como essas animações usam transform e opacity por padrão e são executadas no compositor, elas nunca causam mudanças de layout. O suporte dos navegadores cobre Chrome 115+ e Edge 115+, com o Safari ainda em desenvolvimento. Para efeitos vinculados à rolagem, como parallax, barras de progresso e animações de revelação, esta é a solução mais limpa. Se você deseja abandonar o JavaScript scrolling por completo, a API de animações baseadas em rolagem (scroll-driven animations) é o caminho a seguir.

Por que o Lighthouse não detecta isso

O Lighthouse executa um carregamento de página simulado. Ele não rola a página. Ele não interage com a página após o carregamento. Isso significa que as mudanças de layout acionadas por rolagem são completamente invisíveis em testes de laboratório.

A única maneira de detectar essas mudanças é com Real User Monitoring. Os dados de campo capturam todo o ciclo de vida da página, incluindo cada mudança de layout que acontece enquanto o usuário rola, clica e navega. Se a sua pontuação de CLS do CrUX for pior do que a pontuação de CLS do Lighthouse, as animações acionadas por rolagem são uma das primeiras coisas a investigar. O CoreDash rastreia o CLS de visitantes reais, incluindo todas as mudanças causadas pela rolagem, para que você possa ver exatamente quais elementos são os responsáveis.

Como encontrar mudanças de layout acionadas por rolagem

Abra o Chrome DevTools. Vá para o painel Performance. Inicie o gravador (o ícone de círculo) e role a página para cima e para baixo várias vezes. Pare a gravação. Procure por losangos roxos na trilha Layout Shifts. Se você vir um cluster de mudanças que se alinham com sua atividade de rolagem, você tem um problema de CLS acionado por rolagem. Você também pode usar a extensão do Chrome Core Web Vitals Visualizer para ver o CLS em tempo real enquanto rola.

devtools scroll layout shift

A regra de ouro

Se ele se move na rolagem, anime-o com transform. Se ele esmaece (fade) na rolagem, anime-o com opacity. Essas propriedades são exclusivas do compositor (compositor-only).

Para JavaScript: verifique seus manipuladores de eventos de rolagem, os callbacks do IntersectionObserver e qualquer JavaScript que altere os estilos de elementos em resposta à posição da rolagem. Se usar top, left, margin, width, height ou padding, substitua-o pelo transform equivalente.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

A performance cai no momento que você para de olhar.

Monto o monitoramento, os budgets e o processo. É isso que separa um fix de uma solução.

Vamos conversar
Como as Animações Acionadas por Rolagem Causam CLSCore Web Vitals Como as Animações Acionadas por Rolagem Causam CLS