Como animações disparadas por rolagem causam CLS

Seu header que se esconde no scroll pode estar reprovando o CLS silenciosamente. Veja o motivo e como corrigir.

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

Sempre que me pedem uma auditoria de Cumulative Layout Shift, começo, obviamente, pelos shifts na fase de carregamento. Procuro imagens sem dimensões, anúncios injetados e troca de fontes (FOUT).

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

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

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

O que vemos aqui é um header fixo que se esconde quando o usuário rola para baixo e reaparece quando ele rola para cima. É um padrão que vejo com frequência. Se não for feito da forma correta, causa layout shift a cada mudança de direção no scroll.

Por que shifts disparados por rolagem são diferentes

Normalmente o CLS não acontece após uma interação. O CLS mede layout shifts inesperados — e, após uma interação, é de se esperar que o layout mude. É por isso que a métrica tem um período de tolerância automático de 500 ms. Layout shifts que ocorrem em até 500 milissegundos após uma interação do usuário são excluídos da pontuação do CLS. O navegador gerencia isso ativando e verificando a flag hadRecentInput nesses shifts.

O problema é que isso vale apenas para eventos discretos, como cliques, toques na tela e teclas pressionadas. De acordo com a especificação da Layout Instability, o scroll explicitamente não é uma entrada com exclusão. Gestos de arrastar ou de pinça para zoom também não. Apenas eventos discretos recebem a tolerância de 500 ms.

Isso significa que todo layout shift disparado por um evento de scroll conta para a pontuação do CLS.

Segundo o Web Almanac de 2025, 40% das páginas para celular ainda usam animações sem composição. São animações em propriedades como top, height ou margin que disparam o recálculo de layout a cada frame. Se alguma delas rodar durante o scroll, cada frame contará para o CLS.

O problema do header que se esconde no scroll

Vamos começar pelo problema que encontrei hoje: o 'header que se esconde no scroll'. Um header fixo usa JavaScript para alternar a visibilidade durante a 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';  // esconde
  } else {
    header.style.top = '0px';    // mostra
  }
});

O layout shift é causado pela combinação de transition: top 0.3s ease com a alteração de header.style.top no JavaScript.

Veja o motivo: top é uma propriedade de layout. Quando o navegador processa uma alteração em top, ele executa todo o pipeline de renderização: Style, Layout, Paint, Composite. A cada frame de animação durante essa transição, o navegador recalcula o layout. Cada recálculo gera uma nova entrada de layout shift.

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

Criei uma demonstração reproduzindo exatamente esse comportamento a partir de um site em produção que eu estava auditando e gravei um vídeo. O CLS total passou de 0,1 depois de um pouco de rolagem. É verdade que esse nível de scroll raramente acontece na prática, mas a mecânica não muda. E já vi esse layout shift empurrar sites para além do limite e reprovar o CLS total.

Quais propriedades CSS podem causar layout shifts quando animadas?

Para uma animação causar CLS, ela precisa disparar o Layout. O pipeline de renderização do navegador tem três etapas principais após o cálculo de estilo: Layout, Paint e Composite. Propriedades que afetam apenas a etapa de Composite nunca causam layout shifts. Para saber mais sobre como transições CSS causam layout shifts, veja o artigo complementar.

Propriedades que disparam layout (e causam CLS quando animadas):

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

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

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

transform e opacity rodam na thread do compositor. Elas ignoram tanto o layout quanto o paint. O navegador processa essas propriedades na GPU (é por isso que essas animações funcionam mesmo quando a main thread está ocupada). Como nunca disparam o recálculo de layout, elas jamais geram entradas de layout shift.

Substitua propriedades de layout por transforms

A solução para o header que se esconde no scroll é simples. Substitua a animação de top por transform: translateY().

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

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

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

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

O resultado é o mesmo: o header desliza para cima e desaparece. Mas transform: translateY() roda inteiramente no compositor e nunca causa layout shift.

O mesmo princípio vale para qualquer animação disparada por scroll:

  • Painéis deslizantes: use transform: translateX() em vez de left ou right
  • Elementos expansíveis: use transform: scaleY() em vez de height
  • Elementos com fade: use opacity em vez de visibility combinada com alterações de altura

Outros padrões disparados por scroll que causam CLS

O header que se esconde no scroll é algo que vejo com frequência, mas não é o único. Qualquer JavaScript que altere uma propriedade de layout em resposta a eventos de scroll vai produzir layout shift. Por exemplo:

Efeitos de parallax usando top ou margin-top. Substitua por transform: translateY() ou use a abordagem com perspective e translateZ do CSS para criar parallax apenas com CSS.

Navegação sticky que muda de altura no scroll. Uma barra de navegação que encolhe de 80px para 50px quando o usuário rola a página além de um limite. Se a alteração de altura for animada com transition: height, substitua por transform: scaleY().

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

Alternativa moderna: CSS Scroll-Driven Animations. A API animation-timeline: scroll() permite controlar animações com base no progresso do scroll sem usar nada de JavaScript. Como essas animações usam transform e opacity por padrão e rodam no compositor, elas nunca causam layout shifts. O suporte nos navegadores cobre o Chrome 115+ e o Edge 115+, com o Safari ainda em desenvolvimento. Para efeitos atrelados ao scroll, como parallax, barras de progresso e animações de revelação, essa é a solução mais limpa. Se você quer abandonar o scroll via JavaScript de vez, a API de scroll-driven animations é o melhor caminho.

Por que o Lighthouse não detecta isso

O Lighthouse executa um carregamento simulado da página. Ele não rola a página. Não interage com ela após o carregamento. Isso significa que layout shifts disparados por scroll ficam completamente invisíveis em testes de laboratório.

A única forma de pegar esses shifts é com Real User Monitoring. O field data captura todo o ciclo de vida da página, incluindo cada layout shift que ocorre enquanto o usuário rola, clica e navega. Se o seu CLS no CrUX estiver pior que o CLS no Lighthouse, animações disparadas por scroll são uma das primeiras coisas a investigar. O CoreDash monitora o CLS de visitantes reais, incluindo cada shift causado pela rolagem, para você ver exatamente quais elementos são os responsáveis.

Como encontrar layout shifts disparados por scroll

Abra o Chrome DevTools. Vá até o painel Performance. Inicie a gravação (o ícone de círculo) e role a página para cima e para baixo várias vezes. Pare a gravação. Procure pelos losangos roxos na faixa Layout Shifts. Se vir uma concentração de shifts alinhada à sua atividade de rolagem, você tem um problema de CLS disparado por scroll. Você também pode usar a extensão Core Web Vitals Visualizer do Chrome para ver o CLS em tempo real enquanto rola a página.

A regra prática

Se move no scroll, anime com transform. Se tem fade no scroll, anime com opacity. Essas propriedades rodam exclusivamente no compositor.

No JavaScript: revise os handlers de eventos de scroll, callbacks de IntersectionObserver e qualquer código que altere estilos de elementos em resposta à posição da rolagem. Se encontrar top, left, margin, width, height ou padding, substitua 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.

Arjen Karel

Precisa de um site mais rápido?

Sou o Arjen e há 17 anos conserto sites lentos. Se você está com problemas que não consegue resolver sozinho, me envie sua URL e vamos conversar.

Me envie sua URL
Arjen Karel
Arjen Karel, Consultor de web performance desde 2009

Por que nosso fix não está funcionando?

Às vezes a CDN ainda entrega o HTML antigo, ou o fix entrou no template de desktop e o celular usa outro. Me envie sua URL e o problema, e eu respondo com alguns horários. Primeiro analiso o field data, depois dedicamos uma hora ao seu site, e em até um dia você tem minhas anotações por escrito. €350 sem IVA.

Me envie sua URL

Sem desenvolvedor para fazer o fix? Eu mesmo faço o trabalho, em uma cópia do seu site.

Como animações disparadas por rolagem causam CLS Core Web Vitals Como animações disparadas por rolagem causam CLS