# Jumps: o novo steps() em Web Animation

> Domine steps e jumps em animações CSS para efeitos únicos. Crie animações frame-by-frame incríveis e efeitos escalonados com timing functions discretas. Anime!

URL: https://dpw.dev/css/jumps-steps-css-web-animation/  
Publicado em: 2019-03-14  
Categoria: css  
Tags: interface, motion-ui  
Autor: Tárcio Zemel

> Artigo baseado em [Jumps: The New Steps() in Web Animation](https://danielcwilson.com/blog/2019/02/step-and-jump/).

**Jumps** ("saltos") são os novos valores possíveis para `steps()`, a função CSS de controle de animações. Os novos valores `jump-` auxiliar nas animações web com CSS e poupam ter que fazer cálculos mais complexos.

> **Atenção:** Este artigo discute novas opções de _easing_ em animação web com CSS que, na data de publicação deste artigo, funcionam corretamente somente em Firefox 65+.

A primeira grande mudança para _easings_ em animações web (também conhecida como _time functions_ ou _funções de temporização_) chegou. Após algumas discussões, atualizações na [especificação](https://drafts.csswg.org/css-easing-1/#step-timing-function) e implementações iniciais como uma função separada, o Firefox 65 apresenta 4 novas opções para a função `steps()`:

- `jump-start`
- `jump-end`
- `jump-both`
- `jump-none`

[Exemplo no CodePen](https://codepen.io/anon/pen/gqOBJd)

Como esses novos valores de `step()` se comparam ao que já tivemos e quando são os melhores momentos para usar cada um deles?

## Easings e a função `steps()`

Primeiro, é preciso dar um passo atrás e discutir o que são os easings e o que a função `steps()` permite fazer.

Easings permitem alterar a forma como uma `transition`, CSS `animation` ou uma animação Web Animations API é concluída ao longo do tempo.

```typescript
.mover {
  animation: move 2000ms;
  animation-timing-function: linear; /* easing */
  transform: translateX(0px);
}

@keyframes move {
  100% {
    transform: translateX(200px);
  }
}
```

Com um easing `linear`, tudo se move a um ritmo constante. Mudando isso para `ease-in`, obtém-se algo que começa mais devagar e acelera à medida que chega ao fim da animação.

Com Steps, as coisas são um pouco diferentes, já que é possível passar instruções para que a animação tenha um número específico de _frames_ distintos. Assim, alterar o easing para `steps(2)`, por exemplo, daria uma animação com apenas 2 estados, uma posição inicial e uma final.

Como `steps()` determina cada intervalo de cada step é baseado em um segundo parâmetro (opcional) . É aqui que os novos valores entram em ação e unem os 2 valores existentes `start` e `end`.

## Inícios e Fins (jump-start e jump-end)

Em vez de aprofundar no que significa `start` e `end`, vamos direto ao ponto e dizer que 2 dos 4 valores mencionados acima são de fato aliases desses valores originais:

- `jump-start === start`
- `jump-end === end`

O prefixo `jump` ajuda a explicar as palavras "start" e "end" de forma mais eficaz. Quando usamos `start` ou `jump-start`, estamos dizendo ao cálculo para pular a posição inicial; com `end`/`jump-end`, para pular a posição final.

Você pode pensar que a função `steps(n)` funciona tirando snapshots de uma animação com um ajuste `linear` em intervalos específicos e não exibe cada snapshot até a hora de mostrar o próximo.

Então, quando passamos a instrução `steps(4, jump-end)`, isso acarreta em uma animação "dividida" em 4 seções e captura um snapshot com a posição inicial em cada um desses quartos. Com `steps(5, jump-start)`, a animação é dividida em 5 partes e tomamos a posição final em cada parte.

[Exemplo no CodePen](https://codepen.io/anon/pen/OdyaMz)

Mas por que alguém iria querer pular um estado inicial ou final? O comanda está dizendo ao navegador para ir de um estado específico para outro estado específico diferente com os keyframes da animação, então, não se iria querer sempre ambos os estados presentes na animação resultante?

### Rotações

Fica mais claro perceber os benefícios de pular um início ou fim quando você pensa no ponteiro dos segundos em um relógio: uma animação em execução por 60 segundos para uma rotação completa (`0deg` a `360deg`) e um easing `steps(60)`. Isso resulta em um relógio com ponteiro de segundos que avança para cada marca no relógio (`jump-end`/`end` é assumido quando nenhum segundo parâmetro é especificado).

Sem o salto (_jumping_) do estado final, teríamos uma animação onde o início e o fim estariam no topo (`0deg`) e, assim, o relógio não seria natural, pois ficaria no topo por 2 segundos e faria os 58 segundos restantes.

[Exemplo no CodePen](https://codepen.io/anon/pen/YBzvQQ)

### Sprites

Outra razão importante é animar com _sprites_. Você pode ter frames para animar e transformar a posição de `translateX(0)` para `translate(-100%)` (ou usar `background-position` etc). Se você usar um total de `100%` da largura, o estado final ficará fora da view, então, novamente, pula-se o final para ser possível capturar magicamente cada frame.

[Exemplo no CodePen](https://codepen.io/anon/pen/wNMMYv)

Isso poupa a necessidade de ter que fazer cálculos extras para evitar que o quadro final (em branco) apareça.

## Sem saltos (jump-none)

Às vezes, pular um estado realmente não é o que é preciso fazer. A nova opção `jump-none` permite uma animação que não salta o início ou o fim.

Para qualquer animação com uma contagem de steps de pelo menos 2, o estado inicial e o estado final serão representados. As etapas restantes serão distribuídas uniformemente entre o início e o fim. 3 steps terão seus "snapshots" tirados em `0%`, `50%` e `100%`.

### Mover um objeto

Um caso simples para essa opção é mover um objeto pela tela. É possível mover um objeto do ponto A para o ponto B com um efeito passo-a-passo. Antes, apenas com o salto de `start` ou `end` disponível, não havia uma maneira direta de informar à animação para mostrar as posições inicial e final com frames iguais.

A adição de `jump-none` agora nos dá essa habilidade.

[Exemplo no CodePen](https://codepen.io/anon/pen/BMrBxv)

Com as antigas formas de `steps()`, ainda seria possível fazer isso, mas seria preciso algum cálculo extra e fazer o translation tecnicamente ir além de seu estado inicial ou final. Agora, é mais simples, já que é possível ter certeza de que os estados inicial e final são o que explicitamente se fez deles.

### Opacidade

A opacidade também pode se beneficiar ao garantir que os estados inicial e final estejam sempre visíveis. Digamos que seja preciso um _fade out_ através de uma animação de opacidade escalonada de `1` a `0`. Com `start` ou `end`, o estado totalmente opaco ou totalmente transparente nunca será visto. Mas `jump-none` certifica que ambos sejam vistos.

Uma animação com `steps(2, jump-none)` terá uma animação de liga/desliga direta e `steps(4,jump-none)` resultará em opacidades de `1`, `.6667`, `.3333` and `0`.

[Exemplo no CodePen](https://codepen.io/anon/pen/mvPKwZ)

## Saltando ambos (jump-both)

Mostramos saltos em início, fim e ambos, o que nos deixa agora com o salto de ambos.

[Exemplo no CodePen](https://codepen.io/anon/pen/yZmmgN)

Por um lado, pular ambos permite a completude (já que estamos adicionando `none`, também podemos adicionar `both`), mas também tem potencial, já que as opções de easing podem ser usadas fora da animação.

Os casos de uso para usar easings no contexto de gradientes parecem mais convincentes do que o `jump-both` fornece no contexto da animação.

## Conclusão sobre jumps em animação CSS

Na data de publicação deste artigo, o Chrome já implementou o comportamento `jump-none` sob a discussão de especificações antigas de `frames()`, então, é possível suspeitar que não será um grande sacrifício movê-lo para a nova nomenclatura. Webkit e EdgeHTML ainda não o possuem em nenhuma versão.

Então, essa é a hora de se familiarizar e experimentar ao invés de começar a usar como se não houvesse amanhã enquanto ainda estamos sem fallbacks.

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
