Comece com animações de rolagem no CSS

1. Antes de começar

Animações de rolagem permitem que você controle a reprodução de uma animação com base na posição de rolagem de um contêiner de rolagem. Isso significa que, conforme você rola para cima ou para baixo, a animação vai para frente ou para trás. Além disso, com as animações de rolagem, você também pode controlar uma animação de acordo com a posição de um elemento dentro do seu contêiner de rolagem. Assim, você cria efeitos interessantes, como uma imagem de fundo com efeito paralaxe, barras de rolagem de progresso e imagens que se revelam à medida que aparecem.

Uma novidade do Chrome 114 é o suporte para um conjunto de classes JavaScript e propriedades CSS que permitem a fácil criação de animações declarativas de rolagem. Essas novas APIs trabalham em conjunto com animações já existentes da Web e APIs de animações com CSS.

Este codelab ensina como criar animações de rolagem usando CSS. Após completar este codelab, você vai conhecer as várias propriedades novas de CSS apresentadas por esse recurso interessante, assim como scroll-timeline, view-timeline, animation-timeline, e animation-range.

O que você vai aprender

  • Como criar um efeito de fundo paralaxe com uma linha do tempo de rolagem no CSS.
  • Como criar uma barra de progresso com uma linha do tempo de rolagem no CSS.
  • Como criar um efeito para revelar uma imagem com uma linha do tempo de visualização no CSS.
  • Como segmentar diferentes tipos de períodos da linha do tempo de visualização no CSS.

Recursos necessários

Uma das combinações de aparelhos a seguir:

  • Uma versão recente do Chrome (114 ou posterior) no ChromeOS, macOS, ou Windows
  • Conhecimento básico de HTML
  • Uma compreensão fundamental de CSS, principalmente de animações em CSS

2. Configuração

Tudo o que você precisa para este projeto está em um repositório do GitHub. Para começar, copie e abra o código no ambiente de desenvolvimento de sua preferência.

  1. Abra uma nova aba do navegador e acesse https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab.
  2. Copie o repositório.
  3. Abra o código no ambiente de desenvolvimento integrado de sua preferência.
  4. Execute npm install para instalar as dependências.
  5. Execute npm start e acesse http://localhost:3000/.
  6. Como alternativa, se você não tiver npm instalado, abra o documento src/index.html no Chrome.

3. Saiba mais sobre linhas do tempo de animação

Por padrão, uma animação anexada a um elemento é executada na linha do tempo do documento. Isso significa que, quando a página for carregada, a animação vai avançar conforme o tempo avança. Esta é a linha do tempo de animação padrão e, até agora, era a única à qual você tinha acesso.

Com as animações de rolagem, você ganhará acesso a dois novos tipos de linhas do tempo:

  • Rolar a linha do tempo do progresso
  • Linha do tempo do progresso de visualização

No CSS, essas linhas do tempo podem ser anexadas a uma animação usando a propriedade animation-timeline. Confira o que essas novas linhas do tempo significam e como elas se diferenciam umas das outras.

Rolar a linha do tempo do progresso

Uma linha do tempo do progresso de rolagem é uma linha do tempo de animação vinculada ao progresso na posição de rolagem de um contêiner de rolagem, também chamado de janela ou botão de rolagem, ao longo de um eixo específico. Ele converte uma posição de um período de rolagem em uma porcentagem de progresso ao longo de uma linha do tempo.

A posição de rolagem inicial representa 0% de progresso, e a final representa 100% de progresso. Na visualização a seguir, observe que o progresso aumenta de 0% a 100% à medida que você rola o botão para baixo.

Linha do tempo do progresso de visualização

Esse tipo de linha do tempo está vinculado ao progresso relativo de um elemento específico dentro de um contêiner de rolagem. Assim como uma linha do tempo do progresso de rolagem, o deslocamento de rolagem de um botão é rastreado. Ao contrário de uma linha do tempo do progresso de rolagem, essa é a posição relativa de um objeto dentro desse botão que determina o progresso. Essa funcionalidade é semelhante ao IntersectionObserver, que rastreia o quanto um elemento é visível na rolagem. Se o elemento não estiver visível no botão, não há interseção. Caso esteja visível, mesmo para a menor parte, então há interseção.

A linha do tempo do progresso de visualização se inicia no momento em que um objeto começa a cruzar com o botão de rolagem e termina quando ele para de cruzar com o botão. Na visualização a seguir, observe que o progresso começa a aumentar de 0%, quando o objeto entra no contêiner de rolagem, e atinge 100% quando sai dele.

Por padrão, uma animação vinculada à linha do tempo do progresso de visualização é anexada a todo o período dela. Isso começa a partir do momento em que o objeto entra na janela de rolagem e termina quando ele sai dela.

Também é possível vincular a uma parte específica da linha do tempo do progresso de visualização especificando o período ao qual ele deve ser anexado. Por exemplo, isso pode acontecer apenas quando o objeto estiver entrando no botão de rolagem. Na visualização a seguir, o progresso começa a contar a partir de 0%, quando o objeto entra no contêiner de rolagem, mas chega logo a 100% a partir do momento em que está totalmente intersectado.

Os possíveis períodos da linha do tempo de visualização que você pode segmentar são cover, contain, entry, exit, entry-crossing, e exit-crossing. Esses períodos são explicados posteriormente neste codelab, mas se você não puder esperar para saber, use a ferramenta localizada em https://goo.gle/view-timeline-range-tool para conferir o que cada período representa.

4. Criar um efeito de fundo paralaxe

O primeiro efeito a ser adicionado à página é o de fundo paralaxe, incluído na imagem de fundo principal. Conforme a página é rolada para baixo, a imagem de fundo se move, mas em uma velocidade diferente. Para isso, você precisa usar uma linha do tempo do progresso de rolagem.

Confira as duas etapas para implementar o efeito:

  1. Crie uma animação que mova a posição da imagem de fundo.
  2. Vincule a animação à progressão da rolagem do documento.

Criar uma animação

  1. Para criar uma animação, use um conjunto normal de frames-chave. Nele, mova a posição de fundo de 0% verticalmente para 100%:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. Agora, vincule esses frames-chave ao elemento do corpo:

src/styles.css

body {
  animation: 1s linear move-background;
}

Com esse código, a animação move-background será adicionada ao elemento do corpo. Sua propriedade animation-duration é definida para um segundo e usa um easing linear.

A maneira mais fácil de criar uma linha do tempo do progresso de rolagem é usando a função scroll(). É criada uma linha do tempo de progresso de rolagem anônima que você pode definir, assim como o valor da propriedade animation-timeline.

A função scroll() aceita um <scroller> e um argumento <axis>.

Os valores aceitos para o argumento <scroller> são:

  • nearest. Usa o contêiner de rolagem ancestral mais próximo (padrão).
  • root. Usa a janela de visualização do documento como contêiner de rolagem.
  • self. Usa o próprio elemento como o contêiner de rolagem.

Os valores aceitos para o argumento <axis> são:

  • block. Usa a medida de progresso ao longo do eixo do bloco do contêiner de rolagem (padrão).
  • inline. Usa a medida de progresso ao longo do eixo em linha do contêiner de rolagem.
  • y. Usa a medida do progresso ao longo do eixo y do contêiner de rolagem.
  • x. Usa a medida de progresso ao longo do eixo x do contêiner de rolagem.

Para vincular a animação ao botão de rolagem raiz no eixo do bloco, os valores a serem passadosscroll() são root e block: scroll(root block).

  • Defina scroll(root block) como o valor para a propriedade animation-timeline no corpo. Além disso, como um animation-duration expresso em segundos não faz sentido, defina a duração para auto. Se você não especificar um animation-duration, ele será padronizado como auto.

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

Como o botão de rolagem raiz também é o principal botão mais próximo para o elemento do corpo, você também pode usar um valor de nearest:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(nearest block);
}

Como nearest e block são os valores padrão, eles também podem ser omitidos. Neste caso, o código pode ser simplificado para:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll();
}

Verificar suas alterações

Se tudo tiver dado certo, o resultado deverá ser este:

Caso contrário, confira a ramificação solution-step-1 do código.

5. Criar uma barra de progresso para a galeria de imagem

Na página, há um carrossel horizontal que precisa de uma barra de progresso para indicar qual foto está sendo visualizando no momento.

A marcação para o carrossel fica assim:

src/index.html

<div class="gallery">
  <div class="gallery__scrollcontainer" style="--num-images: 3;">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
  </div>
</div>

Os frames-chave da barra de progresso já estão no lugar e têm a seguinte aparência:

src/styles.css

@keyframes adjust-progress {
  from {
    transform: scaleX(calc(1 / var(--num-images)));
  }
  to {
    transform: scaleX(1);
  }
}

Esta animação precisa estar vinculadoelemento .gallery__progress com a linha do tempo do progresso de rolagem. Como mostrado na etapa anterior, é possível gerar esse resultado criando uma linha do tempo do progresso de rolagem anônima com a função scroll():

src/styles.css

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  animation-timeline: scroll(nearest inline);
}

Uma forma alternativa de definir uma linha do tempo do progresso de rolagem é usar uma já nomeada. É um pouco mais detalhado, mas pode ser útil quando você não está direcionando um botão de rolagem principal ou o botão de rolagem raiz, ou quando a página usa várias linhas do tempo. Dessa forma, você pode identificar uma linha do tempo do progresso de rolagem pelo nome que você deu a ela.

Para criar uma linha do tempo do progresso de rolagem nomeada em um elemento, defina a propriedade CSS do scroll-timeline-name no contêiner de rolagem com um valor de sua preferência.

Como a galeria rola horizontalmente, você também precisa definir a propriedade scroll-timeline-axis. Os valores permitidos são os mesmos do argumento <axis> de scroll().

Por fim, para vincular a animação à linha do tempo do progresso da rolagem, defina a propriedade animation-timeline no elemento que precisa ser animado com o mesmo valor do identificador usado para o scroll-timeline-name.

  • Mudar o documento styles.css para incluir o seguinte:

src/styles.css

.gallery__scrollcontainer {
  /* Create the gallery-is-scrolling timeline */
  scroll-timeline-name: gallery-is-scrolling;
  scroll-timeline-axis: inline;
}

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  /* Set gallery-is-scrolling as the timeline */
  animation-timeline: gallery-is-scrolling;
}

Verificar suas alterações

Se tudo tiver dado certo, o resultado deverá ser este:

Caso contrário, confira a ramificação solution-step-2 do código.

6. Criar animações para as imagens da galeria conforme elas entram e saem da janela de rolagem

Configurar uma linha do tempo do progresso de visualização anônima

Um bom efeito a ser adicionado é fazer as imagens da galeria aparecerem gradualmente à medida que surgem. Para isso, é possível usar uma exibição da linha do tempo do progresso.

Para criar uma linha do tempo do progresso de visualização, use a função view(). Os argumentos aceitos são <axis> e <view-timeline-inset>.

  • O <axis> é o mesmo da linha do tempo do progresso de rolagem e define qual eixo rastrear.
  • Com <view-timeline-inset>, é possível especificar um deslocamento (positivo ou negativo) para ajustar os limites quando um elemento é considerado visível ou não.
  • Os frames-chave já estão no lugar certo, então eles só precisam ser anexados. Para isso, crie uma linha do tempo do progresso de visualização em cada elemento .gallery__entry.

src/styles.css

@keyframes animate-in {
  from {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Limitar o período de uma linha do tempo do progresso de visualização

Se você salvar o CSS e carregar a página, os elementos vão aparecer, mas algo vai parecer errado. Eles começam na opacidade 0 quando ainda estão totalmente fora de vista e só terminam na opacidade 1 quando saem totalmente.

Isso ocorre porque o período padrão para uma linha do tempo do progresso de visualização é o período completo. Esse processo é conhecido como período cover.

  1. Para segmentar apenas o período entry do objeto, use a propriedade animation-range do CSS para limitar quando a animação deve ser executada.

src/styles.css

.gallery__entry {
  animation: linear fade-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry 0% entry 100%;
}

A animação agora vai de entry 0% (o elemento está prestes a entrar no botão de rolagem) para entry 100% (o elemento está totalmente inserido no botão de rolagem).

Os possíveis períodos da linha do tempo de visualização são os seguintes:

  • cover. Representa o período completo da linha do tempo do progresso da visualização.
  • entry. Representa o período durante o qual a caixa principal está entrando no período de visibilidade do progresso da visualização.
  • exit. Representa o período durante o qual a caixa principal está saindo do período de visibilidade do progresso da exibição.
  • entry-crossing. Representa o período durante o qual a caixa principal cruza a borda final.
  • exit-crossing. Representa o período durante o qual a caixa principal cruza a borda inicial.
  • contain. Representa o período durante o qual a caixa principal é totalmente contida ou totalmente coberta por seu período de visibilidade do progresso da visualização dentro da janela de rolagem. Isso depende se o assunto está mais alto ou mais baixo do que o botão de rolagem.

Use a ferramenta localizada em https://goo.gle/view-timeline-range-tool para ver o que cada período representa e como as porcentagens afetam as posições inicial e final.

  1. Como os períodos inicial e final são os mesmos aqui, e os deslocamentos padrão são usados, simplifique o animation-range para um único nome de período de animação:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • Para esmaecer as imagens conforme elas saem do botão de rolagem, você pode fazer o mesmo que a animação de entrada, mas direcionar para um período diferente.

src/styles.css

@keyframes animate-out {
  from {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  to {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in, linear animate-out;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry, exit;
}

Os frames-chave animate-in serão aplicados ao período entry e os frames-chave animate-out ao período exit.

Verificar suas alterações

Se tudo tiver dado certo, o resultado deverá ser este:

Caso contrário, confira a ramificação solution-step-3 do código.

7. Criar animações para as imagens da galeria conforme elas entram e saem da janela de rolagem usando um conjunto de frames-chave

O caso de um conjunto de frames-chave

Em vez de anexar duas animações a períodos diferentes, é possível criar um conjunto de frames-chave que já contenha as informações do período.

A forma dos frames-chave é da seguinte forma:

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. Combine os frames-chave de aparecimento e desaparecimento graduais desta forma:

src/styles.css

@keyframes animate-in-and-out {
  entry 0% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  entry 90% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }

  exit 10% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  exit 100% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}
  1. Quando as informações de período estiverem presentes nos frames-chave, você não vai precisar mais especificar animation-range separadamente. Vincule os frames-chave como a propriedade animation.

src/styles.css

.gallery__entry {
  animation: linear animate-in-and-out both;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Verificar suas alterações

Se tudo tiver dado certo, você deve ter o mesmo resultado da etapa anterior. Caso contrário, consulte a ramificação solution-step-4 do código.

8. Parabéns!

Você concluiu este codelab e agora sabe como criar linhas do tempo de rolagem do progresso e linhas do tempo do progresso de visualização no CSS!

Saiba mais

Recursos: