1

Criando Animações de Scroll Nativas com animation-timeline e scroll() Sem JavaScript

O problema que JavaScript resolveu por tempo demais

Scroll listeners em JavaScript são caros. Cada evento scroll dispara dezenas de vezes por segundo, executa no main thread e, se o handler toca no DOM, força recalculations de layout. A solução clássica envolve requestAnimationFrame, IntersectionObserver ou bibliotecas como GSAP ScrollTrigger, tudo para conectar uma propriedade CSS ao progresso de scroll.

A especificação CSS Scroll-driven Animations (parte do CSS Animations Level 2) resolve isso na camada do navegador. O compositor calcula o progresso do scroll e aplica a animação sem tocar no main thread. O resultado: animações que rodam a 60fps mesmo em páginas pesadas, com zero bytes de JavaScript.

Este post cobre animation-timeline, scroll() e view(), com código funcional que você cola no projeto e testa agora.

Como animation-timeline funciona por baixo

Uma animação CSS tradicional usa tempo como eixo de progresso. Você define animation-duration: 1s e o navegador interpola os keyframes ao longo de 1 segundo. Com animation-timeline, o eixo de progresso deixa de ser tempo e passa a ser a posição de scroll de um container.

/* O navegador mapeia 0% do scroll → 0% dos keyframes
   e 100% do scroll → 100% dos keyframes.
   animation-duration ainda é necessário sintaticamente,
   mas o valor é ignorado: quem controla é o scroll. */
.progress-bar {
  animation: grow-width linear;
  animation-timeline: scroll();
}

@keyframes grow-width {
  from { width: 0%; }
  to { width: 100%; }
}

Dois tipos de timeline existem:

TipoFunção CSSEixo de progressoCaso de uso típico
Scroll Progressscroll()Posição do scroll de um container (0% = topo, 100% = fim)Barra de progresso de leitura, parallax global
View Progressview()Visibilidade de um elemento no viewport (0% = entra, 100% = sai)Fade-in ao scroll, reveal de cards

A diferença entre scroll() e view() define o tipo de animação que você consegue construir.

Barra de progresso de leitura com scroll()

O caso mais direto: uma barra fixa no topo que cresce conforme o usuário rola a página.

<!-- O elemento fica fixo no topo da viewport -->
<div class="reading-progress" aria-hidden="true"></div>
<article class="article-content">
  <h1>Título do artigo</h1>
  <p>Conteúdo longo aqui...</p>
</article>
.reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 4px;
  background: #3b82f6;
  width: 0%;
  z-index: 50;

  /* animation-duration é obrigatório pela spec,
     mas o valor não importa: o scroll controla tudo */
  animation: progress-grow linear;
  animation-timeline: scroll(root block);
}

@keyframes progress-grow {
  from { width: 0%; }
  to { width: 100%; }
}

A função scroll() aceita dois argumentos: o scroller (root, nearest, self) e o eixo (block, inline). scroll(root block) significa "use o scroll vertical do documento inteiro". Se você omitir os argumentos, o padrão é scroll(nearest block), que busca o ancestral scrollable mais próximo.

Reveal animation com view()

Para animar elementos conforme entram no viewport, view() substitui o IntersectionObserver que você usaria em JavaScript.

.card {
  opacity: 0;
  transform: translateY(40px);

  animation: card-reveal linear both;
  animation-timeline: view();

  /* animation-range controla QUANDO a animação começa e termina
     dentro do ciclo de visibilidade do elemento.
     entry 0% = o elemento começa a entrar no viewport
     entry 100% = o elemento está completamente visível */
  animation-range: entry 0% entry 100%;
}

@keyframes card-reveal {
  from {
    opacity: 0;
    transform: translateY(40px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
<div class="card-grid">
  <div class="card">
    <h3>Feature 1</h3>
    <p>Descrição da feature com texto real.</p>
  </div>
  <div class="card">
    <h3>Feature 2</h3>
    <p>Outra descriç

---

Leia o artigo completo em [https://www.vivodecodigo.com.br/react/animacoes-scroll-css-animation-timeline-scroll-sem-javascript](https://www.vivodecodigo.com.br/react/animacoes-scroll-css-animation-timeline-scroll-sem-javascript)
Carregando publicação patrocinada...