Atualizando animação CSS com curvas de movimento

Publicados: 2022-03-10
Resumo rápido ↬ Há animação de interface do usuário e, em seguida, uma boa animação de interface do usuário. Uma boa animação faz você dizer “Uau!” — é suave, bonito e, acima de tudo, natural, não em blocos, rígido ou robótico. Se você frequenta o Dribbble ou o UpLabs, sabe do que estou falando. Com tantos designers incríveis criando animações tão bonitas, qualquer desenvolvedor naturalmente gostaria de recriá-las em seus próprios projetos. Agora, o CSS fornece algumas predefinições para transition-timing-function , como ease-in , ease-out e ease-in-out , que adicionam algum nível de suavidade e realismo, mas são muito genéricos, não são? Quão chato seria se todas as animações na web seguissem as mesmas três funções de tempo?

Há animação de interface do usuário e, em seguida, uma boa animação de interface do usuário. Uma boa animação faz você dizer “Uau!” — é suave, bonito e, acima de tudo, natural, não em blocos, rígido ou robótico. Se você frequenta o Dribbble ou o UpLabs, sabe do que estou falando.

Leitura adicional sobre Smashing:

  • Animações SVG e CSS com caminho de clipe
  • Técnicas Práticas de Animação
  • Criando animações 'desenhadas à mão' com SVG
  • A nova API de animação da Web

Com tantos designers incríveis criando animações tão bonitas, qualquer desenvolvedor naturalmente gostaria de recriá-las em seus próprios projetos. Agora, o CSS fornece algumas predefinições para transition-timing-function , como ease-in , ease-out e ease-in-out , que adicionam algum nível de suavidade e realismo, mas são muito genéricos, não são? Quão chato seria se todas as animações na web seguissem as mesmas três funções de tempo?

(Crédito: Lukas Stranak)
Mais depois do salto! Continue lendo abaixo ↓

Uma das propriedades da transition-timing-function é cubic-bezier(n1, n2, n3, n4) , na qual você pode passar quatro números para criar sua própria função de temporização. No final deste artigo, você saberá exatamente o que esses quatro números representam – ainda assim, acredite em mim, criar quatro números para capturar a transição que você está imaginando em sua cabeça não é nem de longe fácil. Mas graças ao cubic-bezier e Ceasar, você não precisa. Essas ferramentas trazem curvas de movimento para a web.

As curvas de movimento são usadas principalmente por animadores (por exemplo, no Adobe After Effects) para criar animações avançadas e realistas. Com cubic-bezier e Ceasar, você pode simplesmente manipular a forma de uma curva, e esses quatro números ( n1, n2, n3, n4 ) serão preenchidos para você, o que é absolutamente ótimo! Ainda assim, para usar e tirar o máximo proveito das curvas de movimento, você precisa entender como elas funcionam, e é isso que faremos neste artigo. Vamos começar.

Entendendo as curvas de movimento

Uma curva de movimento nada mais é do que um gráfico entre qualquer propriedade animável e o tempo. Uma curva de movimento define como a velocidade de uma animação em execução sob sua influência varia ao longo do tempo.

A curva de movimento é um gráfico entre a propriedade animável e o tempo.
Uma curva de movimento é um gráfico entre uma propriedade animável e o tempo. (Ver versão grande)

Vamos usar a distância ( translateX ) como exemplo de uma propriedade animável. (A explicação vale para qualquer outra propriedade animável.)

Calculando a velocidade no tempo t1 em um gráfico de distância-tempo.
Calculando a velocidade no tempo t1 no gráfico distância-tempo. (Ver versão grande)

Se você já teve alguma experiência com física e cálculo básico, saberá que decifrar a velocidade de um gráfico de distância-tempo é muito simples. A primeira derivada da distância em função do tempo , em relação ao tempo , é a velocidade, o que significa que um objeto seguindo uma curva distância-tempo teria maior velocidade em locais onde a curva é íngreme e menor em locais onde a curva é mais plana . Se você sabe como isso funciona, ótimo! Você está pronto e pode pular para a próxima seção.

Agora, estou ciente de que design e desenvolvimento é um campo diversificado, e nem todos têm a mesma formação. Talvez os dois parágrafos acima fossem todos jargão para você. Não se preocupe. Vamos continuar e entender o jargão.

Considere a caixa vermelha abaixo. Vamos ficar um pouco inexperiente aqui e chamar a caixa vermelha de “Boxy”; será mais fácil se referir a ele dessa maneira. Tudo bem, então o Boxy vai se mover de uma borda da tela para a outra de forma linear, e vamos analisar seu movimento.

Uma das predefinições da transition-timing-function é linear . Para fazer o Boxy se mover, tudo o que fazemos é adicionar a seguinte classe.

 .moveForward { transform: translateX(1000px); }

Para controlar a animação, definiríamos a propriedade de transition para Boxy da seguinte forma:

 #boxy { width: 200px; height: 200px; background: red; transition-property: transform; transition-duration: 1s; transition-timing-function: linear; }

Essa é uma maneira muito detalhada de especificar a transition . Na realidade, você quase sempre encontrará transition escrita em sua forma abreviada:

 #boxy { width: 200px; height: 200px; background: red; transition: transform 1s linear; }

Vamos ver isso.

Boxy em movimento linear
Caixa em movimento linear.

Robótica, não é? Você poderia dizer que esse movimento parece robótico porque é linear, o que é uma resposta perfeitamente plausível. Mas você poderia explicar por quê? Podemos ver que definir resultados linear no movimento robótico, mas o que exatamente está acontecendo nos bastidores? Isso é o que vamos descobrir primeiro; vamos chegar às entranhas e entender por que esse movimento parece robótico, em blocos e não natural.

Vamos começar por representar graficamente o movimento de Boxy para ver se podemos obter alguma informação. Nosso gráfico terá dois eixos, sendo o primeiro a distância e o segundo tempo. Boxy cobre uma distância total de 1000 pixels (distância) em 1 segundo (tempo). Agora, não se assuste com toda a matemática abaixo – é muito simples.

Aqui está o nosso gráfico muito simples, com os eixos mencionados.

Gráfico vazio com eixos
Gráfico vazio com eixos (Ver versão grande)

No momento, está vazio. Vamos preenchê-lo com alguns dados.

Para começar, sabemos que em 0 segundos, quando a animação ainda não começou, Boxy está em sua posição inicial (0 pixels). E depois de 1 segundo, Boxy percorreu um total de 1000 pixels, pousando na borda oposta da tela.

Posições iniciais e finais de Boxy
Posições iniciais e finais de Boxy (Ver versão ampliada)

Vamos plotar esses dados no gráfico.

Gráfico com as posições inicial e final do Boxy plotadas
Gráfico com as posições inicial e final do Boxy plotadas (Ver versão ampliada)

Até agora tudo bem. Mas dois pontos de dados não são suficientes – precisamos de mais. A figura a seguir mostra as posições do Boxy em diferentes pontos do tempo (tudo graças à minha câmera de alta velocidade).

As posições de Boxy em diferentes pontos do tempo
Posições de Boxy em diferentes pontos do tempo (Ver versão ampliada)

Vamos adicionar esses dados ao nosso gráfico.

Gráfico com diferentes posições plotadas
Gráfico com diferentes posições plotadas (Ver versão ampliada)

Você poderia, é claro, ter muito mais pontos de dados para tempos diferentes (por exemplo, 0,375 segundos, 0,6 segundos, etc.), mas o que temos é suficiente para completar nosso gráfico. Juntando todos os pontos, completamos o gráfico. Toca aqui!

Gráfico final
Gráfico final (Ver versão ampliada)

Legal, mas o que isso nos diz? Lembra que começamos nossa investigação com o objetivo de entender por que o movimento linear de Boxy parece artificial e robótico? À primeira vista, este gráfico que acabamos de construir não nos diz nada sobre isso. Precisamos ir mais fundo.

Mantenha o gráfico em mente e vamos falar um minuto sobre velocidade. Eu sei que você sabe o que é velocidade – eu gostaria de colocar em termos matemáticos. Como vai, a fórmula para a velocidade é esta:

Fórmula matemática para velocidade
Fórmula matemática para velocidade (Ver versão ampliada)

Portanto, se um carro percorre uma distância de 100 quilômetros em 1 hora, dizemos que sua velocidade é de 100 quilômetros por hora.

Representando a velocidade
Representando a velocidade (Ver versão ampliada)

Se o carro dobrar sua velocidade, ele começará a percorrer o dobro da distância (200 quilômetros) no mesmo intervalo (1 hora), ou seja, percorrerá a distância original de 100 quilômetros na metade do tempo (0,5 horas). . Faz sentido?

Da mesma forma, se o carro reduzisse a velocidade pela metade (ou seja, reduzisse a velocidade pela metade), ele começaria a percorrer uma distância de 50 quilômetros no mesmo intervalo (1 hora), ou seja, percorreria a distância original de 100 quilômetros. quilômetros no dobro do tempo (2 horas).

Excelente! Com isso fora do caminho, vamos continuar de onde paramos. Estávamos tentando descobrir como o gráfico entre distância e tempo pode nos ajudar a entender por que o movimento linear de Boxy parece robótico.

Ei, espere um segundo! Temos um gráfico entre a distância e o tempo, e a velocidade pode ser calculada a partir da distância e do tempo, não é? Vamos tentar calcular a velocidade do Boxy em diferentes intervalos de tempo.

Calculando a velocidade em diferentes intervalos
Calculando a velocidade em diferentes intervalos (Ver versão ampliada)

Aqui, eu escolhi três intervalos de tempo diferentes: um perto do início, um no meio e um no final perto da posição final. Como é evidente, em todos os três intervalos, Boxy tem exatamente a mesma velocidade (s1 = s2 = s3) de 1000 pixels por segundo; ou seja, não importa qual intervalo você escolha no gráfico acima, você encontrará Boxy movendo-se a 1000 pixels por segundo. Não é estranho? As coisas na vida real não se movem em uma velocidade constante; eles começam devagar, aumentam gradualmente sua velocidade, se movem por um tempo e depois desaceleram novamente antes de parar, mas Boxy começa abruptamente com uma velocidade de 1000 pixels por segundo, movendo-se com a mesma velocidade e parando abruptamente exatamente na mesma velocidade. É por isso que o movimento de Boxy parece robótico e não natural. Vamos ter que mudar nosso gráfico para corrigir isso. Mas antes de mergulhar, precisamos saber como as mudanças na velocidade afetarão o gráfico desenhado entre distância e tempo. Preparar? Isto vai ser divertido.

Vamos dobrar a velocidade do Boxy e ver como a aparência do gráfico muda em resposta. A velocidade original do Boxy, como calculamos acima, é de 1000 pixels por segundo. Como dobramos a velocidade, o Boxy agora poderá cobrir a distância de 1.000 pixels na metade do tempo — ou seja, em 0,5 segundos. Vamos colocar isso em um gráfico.

Gráfico mostrando a velocidade dupla
Gráfico mostrando a velocidade dupla (Ver versão ampliada)

E se triplicarmos a velocidade? Boxy agora cobre 1000 pixels em um terço do tempo (um terço de segundo).

Gráfico mostrando a velocidade tripla
Gráfico mostrando a velocidade tripla (Ver versão ampliada)

Hum, notou algo? Observe como, quando o gráfico muda, o ângulo que a linha faz com o eixo do tempo aumenta à medida que a velocidade aumenta.

Muito bem, vamos em frente e reduzimos pela metade a velocidade do Boxy. Reduzir pela metade sua velocidade significa que o Boxy será capaz de cobrir apenas 500 pixels (metade da distância original) em 1 segundo. Vamos colocar isso em um gráfico.

Gráfico mostrando meia velocidade
Gráfico mostrando meia velocidade (Ver versão ampliada)

Vamos desacelerar um pouco mais o Boxy, tornando a velocidade um terço do original. Boxy será capaz de cobrir um terço da distância original em 1 segundo.

Gráfico mostrando um terço da velocidade
Gráfico mostrando um terço da velocidade (Ver versão ampliada)

Veja um padrão? A linha fica cada vez mais íngreme à medida que aumentamos a velocidade de Boxy e começa a se achatar à medida que desaceleramos Boxy.

A linha fica mais íngreme à medida que a velocidade aumenta e fica mais plana à medida que a velocidade diminui
A linha fica mais íngreme à medida que a velocidade aumenta e se aplana à medida que a velocidade diminui. (Ver versão grande)

Isso faz sentido porque, para uma linha mais íngreme, um pequeno avanço no tempo produz uma mudança muito maior na distância, implicando em maior velocidade.

Uma pequena mudança no tempo produz uma mudança relativamente grande na distância, tornando o gráfico mais inclinado.
Uma pequena mudança no tempo produz uma mudança relativamente grande na distância, tornando o gráfico mais inclinado. (Ver versão grande)
Uma pequena mudança no tempo produz uma mudança relativamente grande na distância, tornando o gráfico mais inclinado.
Uma pequena mudança no tempo produz uma mudança relativamente grande na distância, tornando o gráfico mais inclinado. (Ver versão grande)

Por outro lado, para uma linha menos íngreme, uma grande mudança no tempo produz apenas uma pequena mudança na distância, o que significa uma velocidade menor.

Mudança no tempo versus mudança na distância em um gráfico que é menos íngreme
Mudança no tempo versus mudança na distância em um gráfico menos inclinado (Ver versão ampliada)
Mudança no tempo versus mudança na distância em um gráfico que é menos íngreme
Mudança no tempo versus mudança na distância em um gráfico menos inclinado (Ver versão ampliada)

Com todas as mudanças que fizemos, Boxy ainda está se movendo de forma linear, apenas em velocidades diferentes. No entanto, com nosso conhecimento recém-adquirido de como as mudanças na distância versus o tempo podem afetar a velocidade, podemos experimentar e desenhar um gráfico que faça o Boxy se mover de uma maneira que pareça natural e realista.

Vamos levá-lo passo a passo. Primeiro, as coisas na vida real começam lentas e aumentam lentamente de velocidade. Então, vamos fazer isso.

Em todas as iterações do gráfico mostrado abaixo, você notará que os pontos nos cantos opostos permanecem fixos. Isso ocorre porque não estamos alterando a duração da animação, nem a distância que o Boxy percorre.

Construindo uma curva de movimento personalizada
Construindo uma curva de movimento personalizada (Ver versão ampliada)

Se o Boxy seguir o gráfico acima, ele se moverá em uma velocidade mais lenta por 0,25 segundos, porque a linha é menos íngreme começando de 0 a 0,25 segundos, e então mudará abruptamente para uma velocidade mais alta após 0,25 segundos (o motivo é que a linha no gráfico fica mais inclinada após 0,25 segundos). No entanto, precisaremos suavizar essa transição; não queremos cantos — afinal, chama-se curva de movimento. Vamos converter esse canto em uma curva.

Construindo uma curva de movimento personalizada
Construindo uma curva de movimento personalizada (Ver versão ampliada)

Observe a transição suave pela qual Boxy passa do repouso para o aumento gradual da velocidade.

Boxy seguindo a curva de movimento acima
Caixa seguindo a curva de movimento acima (Ver versão ampliada)

Boa! Em seguida, objetos na vida real desaceleram progressivamente antes de parar. Vamos mudar o gráfico para que isso aconteça. Novamente, pegaremos um ponto no tempo após o qual gostaríamos que o Boxy começasse a desacelerar. Que tal cerca de 0,6 segundos? Já alisei o canto da transição para uma curva aqui.

Curva de movimento personalizada final
Curva de movimento personalizada final (Ver versão grande)

Olha o Boxy go! Muito mais natural, não é?

Boxy seguindo a curva de movimento personalizada
Boxy seguindo a curva de movimento personalizada (Ver versão ampliada)

A curva que desenhamos no lugar do canto é na verdade uma coleção de muitos pequenos segmentos de linha; e, como você já sabe, quanto mais íngreme a linha no gráfico, maior a velocidade, e quanto mais plana a linha, mais lenta a velocidade. Observe como na parte esquerda da imagem, os segmentos de linha que compõem a curva ficam cada vez mais íngremes, resultando em um aumento gradual da velocidade, e progressivamente se achatam no lado direito, resultando na diminuição progressiva da velocidade?

Uma curva nada mais é do que uma coleção de muitos segmentos de linha.
Uma curva nada mais é do que uma coleção de muitos segmentos de linha. (Ver versão grande)

Com todo esse conhecimento, entender as curvas de movimento se torna muito mais fácil. Vejamos alguns exemplos.

(Ver versão grande)
Exemplo 1
Exemplo 1 (Ver versão grande)
(Ver versão grande)
Exemplo 2
Exemplo 2 (Ver versão grande)
(Ver versão grande)
Exemplo 3
Exemplo 3 (Ver versão grande)

Usando curvas de movimento na animação da interface do usuário

Na próxima vez que você precisar animar um elemento de interface do usuário, terá o poder das curvas de movimento à sua disposição. Seja uma barra deslizante, uma janela modal ou um menu suspenso, adicionar a quantidade certa de animação e torná-la suave e natural aumentará muito a qualidade da interface do usuário. Isso fará com que a interface do usuário se sinta bem. Pegue o menu deslizante abaixo:

Veja o Pen nJial de Nash Vail (@nashvail) no CodePen.

Veja o Pen nJial de Nash Vail (@nashvail) no CodePen.

Clicar no menu de hambúrguer traz o menu da esquerda, mas a animação parece em blocos. A linha 51 do CSS mostra que a animação tem transition-timing-function definida como linear . Podemos melhorar isso. Vamos para o cubic-bezier e criar uma função de temporização personalizada.

Se você está lendo isso, é seguro assumir que você é um designer ou um desenvolvedor ou ambos e, portanto, não é estranho às curvas cúbicas de bezier; há uma boa chance de você os ter encontrado pelo menos uma vez. As curvas de Bezier são uma maravilha. Eles são usados ​​principalmente em computação gráfica para desenhar formas e são usados ​​em ferramentas como Sketch e Adobe Illustrator para desenhar gráficos vetoriais. A razão pela qual as curvas cúbicas de bezier são tão populares é que elas são tão fáceis de usar: basta modificar as posições dos quatro pontos diferentes e criar o tipo de curva que você precisa.

Como sempre sabemos os estados inicial e final do objeto animado, podemos corrigir dois dos pontos. Isso deixa apenas dois pontos cujas posições temos que modificar. Os dois pontos fixos são chamados de pontos de ancoragem e os dois restantes são pontos de controle.

Partes de uma curva bezier
Partes de uma curva bezier (Ver versão ampliada)

Como você se lembra, cubic-bezier aceita quatro números ( n1, n2, n3, n4 ) quando você cria uma transition-timing-function personalizada . Esses quatro números representam nada além das posições dos dois pontos de controle: n1, n2 representam as coordenadas xey do primeiro ponto de controle e n3, n4 representam as coordenadas do segundo ponto de controle. Como alterar a posição dos pontos de controle mudará a forma da curva e, portanto, nossa animação geral, o resultado é o mesmo quando qualquer um ou todos os n1, n2, n3, n4 são modificados. Por exemplo, a figura abaixo representa cubic-bezier(.14, .78, .89, .35) :

Uma curva cúbica de bezier representando (0,14, 0,78, 0,89, 0,35).
Uma curva bezier cúbica representando (.14, .78, .89, .35) (Ver versão ampliada)

A matemática por trás dessas curvas aparentemente simples é fascinante.

Tudo bem, tudo bem, vamos voltar para onde estávamos indo com cubic-bezier: criando uma transition-timing-function personalizada . Eu quero o tipo de animação em que o menu desliza muito rapidamente e depois desacelera graciosamente e termina:

Ajustando a curva cúbica de bezier
Ajustando a curva cúbica de bezier (Ver versão ampliada)

Este parece ser bom. A animação começará rápido e depois desacelerará, em vez de se mover a uma velocidade constante. Vou simplesmente copiar cubic-bezier(.05, .69, .14, 1) do topo da página e substituir linear por ele.

Veja o Pen nJial de Nash Vail (@nashvail) no CodePen.

Veja o Pen nJial de Nash Vail (@nashvail) no CodePen.

Veja a diferença? A segunda iteração parece muito mais natural e atraente. Imagine se cada animação em sua interface do usuário seguisse uma função de tempo natural. Quão grande seria isso?

Como vimos, as curvas de movimento não são nada complicadas. Eles são muito fáceis de entender e usar. Com eles, você pode levar sua interface do usuário para o próximo nível.

Espero que você tenha aprendido como as curvas de movimento funcionam. Se você estava passando por muitas tentativas e erros para fazer com que as curvas de movimento funcionassem da maneira que você deseja, ou se você não as estava usando, agora você deve se sentir confortável em dobrá-las à sua vontade e criar belas animações. Porque, afinal, a animação importa.