10 princípios para animações web fluidas
O guia completo para conseguir animações a 60fps com CSS

Desde que lançamos o Gyroscope no ano passado, muita gente pergunta sobre a biblioteca de JavaScript que usamos nas nossas animações. A gente pensou em liberar ela para o público, mas não é aí que a mágica acontece.
Não queremos que as pessoas sintam que dependem de algum plugin especial de JavaScript que resolve esses problemas por mágica. Na maior parte, a gente só está aproveitando as melhorias recentes de desempenho dos navegadores, das GPUs e da especificação do CSS3.
Não existe bala de prata para boas animações, além de dedicar muito tempo a testar e otimizar. Mesmo assim, depois de anos de experimentação e de esbarrar nos limites de desempenho dos navegadores, chegamos a uma série de princípios de design & código que costumam resultar em animações bonitas de forma confiável. Essas técnicas devem te dar páginas que parecem fluidas, funcionam em navegadores modernos de desktop e mobile e, o mais importante, são fáceis de manter.

A tecnologia e a implementação vão ser um pouco diferentes para cada um, mas os princípios gerais devem ajudar em quase qualquer situação.
O que é uma animação?
Animações existem desde antes da internet, e fazê-las bem é algo que dá para passar a vida inteira aprendendo. Só que existem restrições e desafios específicos quando você as faz para a internet.
Para um desempenho fluido de 60fps, cada quadro precisa ser renderizado em menos de 16ms! Isso não é muito tempo, então precisamos encontrar jeitos bem eficientes de renderizar cada quadro para manter a fluidez.
Existem dezenas de jeitos de fazer animações na web. Por exemplo, a tira de filme é uma abordagem que existe desde antes da internet, com quadros desenhados à mão ligeiramente diferentes sendo trocados muitas vezes por segundo para criar a ilusão de movimento.
O Twitter usou recentemente essa abordagem simples na nova animação do coração deles, passando por um sprite de quadros.

Esse efeito poderia ter sido feito com um monte de elementos minúsculos animando individualmente, ou talvez como um SVG, mas isso seria complexo à toa e provavelmente não ficaria tão fluido.

Em muitos casos, você vai querer usar a propriedade transition do CSS para animar automaticamente um elemento conforme ele muda. Essa técnica também é conhecida como “tweening”, ou seja, a transição entre dois valores diferentes. Ela tem a vantagem de ser fácil de cancelar ou reverter sem precisar construir toda essa lógica. É ideal para animações do tipo “configurou e esqueceu”, como sequências de abertura etc., ou interações simples como hovers.
Leitura complementar: All you need to know about CSS Transitions

Em outros casos, a propriedade animation do CSS, baseada em keyframes, pode ser ideal para detalhes de fundo que rodam continuamente. Por exemplo, os anéis do logo do Gyroscope estão programados para girar sem parar. Outro tipo de coisa que se beneficia da sintaxe de animation do CSS são as relações de engrenagem.
Então, sem mais delongas, aqui vão algumas dicas que, espero, vão melhorar muito o desempenho das suas animações…
#1
Não mude nenhuma propriedade além de opacity ou transform!
Mesmo que você ache que talvez esteja tudo bem, não mude!
Só esse princípio básico já te leva 80% do caminho, até no mobile. Você provavelmente já ouviu isso antes, não é uma ideia original, mas raramente é seguida. É o equivalente web de “coma bem e se exercite”, que soa como um bom conselho mas você provavelmente ignora.
É bem direto quando você se acostuma a pensar assim, mas pode ser um salto grande para quem está acostumado a animar propriedades tradicionais de CSS.
Por exemplo, se você quisesse deixar algo menor, poderia usar transform: scale() em vez de mudar a largura. Se quisesse mover, em vez de mexer em margins ou paddings, o que exigiria reconstruir o layout inteiro da página a cada quadro, bastaria usar um simples transform: translateX ou transform: translateY.
Por que isso funciona?
Para um ser humano, mudar width, margin ou outras propriedades pode não parecer grande coisa, ou até parecer preferível por ser mais simples, mas em termos do que o computador precisa fazer são mundos diferentes, e um deles é muito, muito pior.
Os times dos navegadores fizeram um ótimo trabalho otimizando essas operações. Transforms são bem fáceis de executar com eficiência e muitas vezes conseguem usar a sua placa de vídeo sem re-renderizar os elementos.
Você pode enlouquecer no carregamento inicial da página: arredonde todos os cantos, use imagens, coloque sombra em tudo e, se estiver se sentindo especialmente imprudente, faça até um blur dinâmico. Se acontece só uma vez, alguns milissegundos a mais de cálculo não fazem diferença. Mas, depois que o conteúdo está renderizado, você não quer ficar recalculando tudo.
Leitura complementar: Moving elements with translate (Paul Irish)
#2
Esconda conteúdo bem diante dos olhos.
Use pointer-events: none junto com opacidade zero para esconder elementos
Esse aqui pode ter algumas ressalvas entre navegadores, mas se você está construindo só para webkit e outros navegadores modernos, ele vai facilitar muito a sua vida.
Muito tempo atrás, quando as animações tinham que ser feitas pelo animate() do jQuery, boa parte da complexidade de fazer coisas aparecerem e sumirem vinha de alternar entre display: none e block na hora certa. Cedo demais e a animação não terminava; tarde demais e você ficava com conteúdo invisível de opacidade zero cobrindo a página. Tudo precisava de callbacks para fazer a limpeza depois que a animação acabava.
A propriedade pointer-events do CSS (que já existe faz um bom tempo, mas não é muito usada) basicamente faz com que as coisas não respondam a cliques ou interações, como se elas nem estivessem ali. Dá para ligar e desligar facilmente pelo CSS sem interromper animações nem afetar a renderização ou a visibilidade de nenhuma forma.
Combinada com uma opacidade zero, ela tem basicamente o mesmo efeito do display none, mas sem o impacto de desempenho de disparar novas renderizações. Quando quero esconder alguma coisa, normalmente só coloco a opacidade em 0 e desligo os pointer-events, e depois esqueço o elemento sabendo que ele vai se virar sozinho.
Isso funciona especialmente bem com elementos posicionados de forma absoluta, porque você pode ter certeza de que eles não estão causando absolutamente nenhum impacto no resto da página.
Também te dá um pouco mais de folga, já que o tempo não precisa ser perfeito. Não é o fim do mundo se um elemento ficar clicável ou cobrindo outras coisas por um segundo a mais do que ficou visível, ou se ele só virar clicável depois de aparecer por completo.
#3
Não anime tudo ao mesmo tempo.
Use coreografia.
Uma animação sozinha pode ser fluida, mas junto com muitas outras provavelmente vai travar. É bem fácil criar uma demo básica de quase qualquer coisa rodando lisinho, e uma ordem de grandeza mais difícil manter esse desempenho num site inteiro. Por isso é importante agendar tudo direito.
Você vai querer espalhar os tempos para que nem tudo comece ou rode exatamente no mesmo instante. Normalmente, 2 ou 3 coisas conseguem se mover ao mesmo tempo sem perder velocidade, ainda mais se foram disparadas em momentos um pouco diferentes. Mais do que isso e você arrisca picos de travamento.
A não ser que exista literalmente uma coisa só nas suas páginas, é importante entender o conceito de coreografia. Pode parecer um termo de dança, mas é igualmente importante para animar interfaces. As coisas precisam entrar pela direção certa e na hora certa. Mesmo sendo todas separadas, elas devem parecer parte de uma unidade bem desenhada.
O material design do Google tem sugestões interessantes sobre esse assunto. Não é o único jeito certo de fazer as coisas, mas é algo em que você deveria pensar e testar.

Leitura complementar: Google Material Design · Motion
#4
Aumentar levemente os delays de transição facilita coreografar o movimento.
Coreografar animações é muito importante e vai exigir bastante experimentação e teste até parecer certo. Mesmo assim, o código para isso não precisa ser muito complicado.
Eu normalmente mudo uma única classe num elemento pai (muitas vezes no body) para disparar um monte de transições, e cada uma tem o seu próprio transition-delay variado para entrar na hora certa. Do ponto de vista do código, você só precisa se preocupar com uma mudança de estado, e não manter dezenas de tempos no seu JavaScript.

Escalonar uma série de elementos é um jeito fácil e simples de coreografá-los. É poderoso porque, ao mesmo tempo que fica bonito, ainda te dá um desempenho precioso; lembre-se de que você quer ter só algumas poucas coisas acontecendo ao mesmo tempo. Você vai querer espalhá-las o suficiente para cada uma parecer fluida, mas não tanto a ponto de tudo parecer lento demais. Precisa haver sobreposição suficiente para parecer um fluxo contínuo, e não uma fila de coisas isoladas.
Exemplo de código
Existem algumas técnicas simples para escalonar os seus elementos, ainda mais se for uma lista longa. Se são menos de 10 itens, ou uma quantidade bem previsível (como numa página estática), eu normalmente defino os valores no CSS. É o jeito mais simples e mais fácil de manter.

Para listas mais longas ou conteúdo muito dinâmico, os tempos podem ser definidos dinamicamente percorrendo cada item.

Geralmente são duas variáveis: o seu delay base e o intervalo de tempo entre cada item. É um equilíbrio delicado de achar, mas quando você acerta o conjunto de números fica perfeito.
#5
Use um multiplicador global para desenhar em câmera lenta
E depois acelere tudo.
No design de animação, o tempo é tudo. 20% do trabalho é implementar alguma coisa, e os outros 80% é encontrar os parâmetros & durações certos para deixar tudo sincronizado e fluido.
Principalmente quando você trabalha a coreografia de várias coisas e tenta espremer desempenho e simultaneidade da página, ver tudo em câmera lenta facilita muito.
Seja usando Javascript ou algum pré-processador de CSS como o SASS (que a gente ama), deve ser bem simples fazer uma continha a mais e construir com variáveis.
Você deve garantir que seja prático testar velocidades ou tempos diferentes. Por exemplo, se uma animação engasga até a 1/10 da velocidade, pode ter algo fundamentalmente errado. Se ela roda lisinho quando esticada 50x, então é só uma questão de achar a maior velocidade em que ela ainda funciona. Pode ser difícil notar problemas de 5 milissegundos na velocidade normal, mas se você desacelerar tudo eles ficam extremamente óbvios.
Principalmente em animações muito complexas, ou para resolver gargalos de desempenho difíceis, poder ver as coisas em câmera lenta pode ser muito útil.
A ideia principal é que você quer empacotar um monte de detalhes perfeitos enquanto está lento, e depois acelerar tudo para ficar impecável. Vai ser bem sutil, mas o usuário vai notar a fluidez e os detalhes.
Esse recurso, aliás, faz parte do OS X: se você segurar shift e clicar no botão de minimizar ou no ícone de um app, vai ver a animação em câmera lenta. Em certo momento, a gente até implementou esse recurso de câmera lenta no Gyroscope, ativado ao apertar shift.
#6
Grave vídeos da sua UI e assista de novo para ganhar uma valiosa perspectiva de terceira pessoa.
Às vezes uma perspectiva diferente te ajuda a enxergar as coisas com mais clareza, e vídeo é um ótimo jeito de fazer isso.
Tem gente que monta um vídeo no after effects e depois tenta implementar aquilo num site. Eu costumo acabar fazendo o caminho contrário, tentando montar um bom vídeo a partir da UI de um site.
Conseguir postar um Vine* ou vídeo de alguma coisa é uma régua bem alta. Um dia eu estava empolgado com algo que tinha construído e tentei fazer uma gravação para mostrar a uns amigos.
Só que, quando assisti de novo, notei um monte de coisas que não estavam boas. Tinha um pico grande de travamento e todos os tempos estavam levemente errados. Me deu um aperto e, em vez de mandar, percebi que ainda tinha bastante trabalho pela frente.
É fácil passar batido por esses detalhes enquanto você usa em tempo real, mas assistir às animações em vídeo, várias e várias vezes ou em câmera lenta, deixa qualquer problema extremamente óbvio.
Dizem que a câmera engorda 10 libras. Talvez ela também acrescente 10 quadros.
Virou uma parte importante do meu fluxo de trabalho assistir a vídeos em câmera lenta das minhas páginas e fazer mudanças se algum quadro não parecer certo. É fácil culpar os navegadores lentos, mas com mais otimização e teste dá para resolver todos esses problemas.
Quando você não sentir mais vergonha de flagrar picos de travamento no vídeo e achar que o vídeo está bom o bastante para compartilhar, então a página provavelmente está pronta para lançar.
#7
Atividade de rede pode causar travamento.
Você deve pré-carregar ou atrasar requisições HTTP grandes
Imagens são grandes culpadas nesse caso, sejam algumas poucas bem grandes (um fundo grande, talvez), um monte de pequenininhas (imagine 50 avatares carregando) ou só muito conteúdo (uma página longa com imagens até o rodapé).
Quando a página está carregando, um monte de coisa está sendo inicializada e baixada. Ter analytics, anúncios e outros scripts de terceiros piora ainda mais. Às vezes, atrasar todas as animações em algumas centenas de milissegundos depois do carregamento faz maravilhas pelo desempenho.
Não otimize demais para isso enquanto não for necessário, mas uma página complicada pode exigir delays e tempos de conteúdo bem precisos para rodar liso. Em geral, você vai querer carregar o mínimo de dados possível no começo e depois continuar carregando o resto da página assim que o trabalho pesado e as animações de abertura terminarem.
Em páginas com muitos dados, o trabalho de carregar tudo pode ser considerável. Uma animação que funciona bem com conteúdo estático pode desmoronar quando você começa a carregá-la com dados reais ao mesmo tempo. Se algo parece que deveria funcionar, ou às vezes roda liso e às vezes não, eu sugiro checar a atividade de rede para garantir que você não está fazendo outras coisas ao mesmo tempo.
#8
Não amarre nada direto no scroll.
Parece uma ideia legal, mas realmente não é boa.
Animações baseadas em scroll ganharam bastante popularidade nos últimos anos, principalmente as que envolvem parallax ou algum outro efeito especial. Se são bom design ou não é discutível, mas existem jeitos melhores e piores de implementá-las tecnicamente.
Um jeito moderadamente performático de fazer coisas dessa categoria é tratar o momento em que se atinge certa distância de rolagem como um evento, e disparar as coisas uma vez só. A não ser que você saiba muito bem o que está fazendo, eu sugiro evitar essa categoria, já que é fácil demais dar errado e muito difícil de manter.
Pior ainda é construir a sua própria barra de rolagem em vez de usar a padrão, o famoso scrolljacking. Por favor, não faça isso.
Essa é uma daquelas regras especialmente úteis para o mobile, mas provavelmente também é boa prática para a experiência de usuário ideal.
Se você quiser mesmo um tipo específico de experiência focada em rolagem ou em algum evento especial, eu sugiro construir um protótipo rápido para garantir que ela tem bom desempenho antes de gastar muito tempo desenhando.
#9
Teste no mobile cedo & sempre.
A maioria dos sites é construída num computador e provavelmente testada com mais frequência na mesma máquina em que foi construída. Assim, a experiência mobile & o desempenho das animações costumam ficar em segundo plano. Algumas tecnologias (como canvas) ou técnicas de animação podem não ter o mesmo desempenho no mobile.
Mesmo assim, se for codado & otimizado direito (veja a regra #1), a experiência mobile pode ser até mais fluida do que num computador. Otimizar para mobile já foi um assunto bem espinhoso, mas os iPhones novos hoje são mais rápidos que a maioria dos laptops! Se você vem seguindo as dicas anteriores, é bem possível que você acabe com um ótimo desempenho no mobile já de saída.

O uso no mobile vai ser uma parte grande e muito importante de quase qualquer site. Pode parecer extremo, mas eu sugiro usar o site exclusivamente pelo celular por uma semana inteira. Ser obrigado a usar a versão mobile não deveria parecer um castigo, mas muitas vezes parece.
Continue fazendo melhorias de design & de desempenho até ele parecer tão bem-acabado e prático quanto a versão grande do site.
Se você se forçar a usar só o seu site mobile por uma semana, provavelmente vai acabar otimizando ele para ser uma experiência ainda melhor que a grande. Vale a pena o incômodo de usar isso todo dia, se isso significa que os problemas são resolvidos antes de os seus usuários passarem por eles!
#10
Teste com frequência em vários dispositivos
Tamanho de tela, densidade ou aparelho podem ter implicações enormes
Existem muitos fatores além de mobile vs desktop que podem afetar drasticamente o desempenho, como a tela ser “retina” ou não, a contagem total de pixels da janela, a idade do hardware etc.
Mesmo Chrome e Safari sendo dois navegadores baseados em Webkit com sintaxe parecida, cada um também tem as suas manias. Cada atualização do Chrome pode consertar coisas e introduzir bugs novos, então você precisa estar sempre atento.
Claro que você não quer construir só para o menor denominador comum, então encontrar jeitos espertos de adicionar ou remover os incrementos progressivamente pode ser muito útil.
Eu alterno com frequência entre o meu MacBook Air minúsculo e o meu iMac enorme, e cada troca revela pequenos problemas e melhorias a fazer, principalmente em desempenho de animação, mas também no design geral, na densidade de informação, na legibilidade etc.
Media queries podem ser ferramentas muito poderosas para lidar com esses segmentos diferentes: estilizar de forma diferente por altura ou largura é um uso típico de media queries, mas elas também podem ser usadas para segmentar por densidade de pixels ou outras propriedades. Descobrir o sistema operacional e o tipo de aparelho também pode ser útil, já que as características de desempenho no mobile podem ser bem diferentes das dos computadores.

Espero que você ache essas técnicas úteis no seu próximo projeto. Boa sorte!


