Atualizando animação CSS com curvas de movimento
Publicados: 2022-03-10transition-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?
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.
Vamos usar a distância ( translateX
) como exemplo de uma propriedade animável. (A explicação vale para qualquer outra propriedade animável.)
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.
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.
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.
Vamos plotar esses dados no gráfico.
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).
Vamos adicionar esses dados ao nosso gráfico.
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!
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:
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.
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.
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.
E se triplicarmos a velocidade? Boxy agora cobre 1000 pixels em um terço do tempo (um terço de segundo).
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.
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.
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.
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.
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.
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.
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.
Observe a transição suave pela qual Boxy passa do repouso para o aumento gradual da velocidade.
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.
Olha o Boxy go! Muito mais natural, não é?
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?
Com todo esse conhecimento, entender as curvas de movimento se torna muito mais fácil. Vejamos alguns exemplos.
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.
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.
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)
:
(.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:
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 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.