Como criar animações CSS de alto desempenho

Este guia ensina como criar animações CSS de alto desempenho.

Consulte Por que algumas animações são lentas? para entender a teoria por trás dessas recomendações.

Compatibilidade com navegadores

Todas as propriedades CSS recomendadas neste guia têm boa compatibilidade entre navegadores.

transform

Browser Support

  • Chrome: 36.
  • Edge: 12.
  • Firefox: 16.
  • Safari: 9.

Source

opacity

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 2.

Source

will-change

Browser Support

  • Chrome: 36.
  • Edge: 79.
  • Firefox: 36.
  • Safari: 9.1.

Source

Mover um elemento

Para mover um elemento, use os valores de palavra-chave translate ou rotation da propriedade transform.

Por exemplo, para deslizar um item para a visualização, use translate.

.animate {
  animation: slide-in 0.7s both;
}

@keyframes slide-in {
  0% {
    transform: translateY(-1000px);
  }
  100% {
    transform: translateY(0);
  }
}

Use rotate para girar elementos. O exemplo a seguir gira um elemento em 360 graus.

.animate {
  animation: rotate 0.7s ease-in-out both;
}

@keyframes rotate {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

Redimensionar um elemento

Para redimensionar um elemento, use o valor de palavra-chave scale da propriedade transform.

.animate {
  animation: scale 1.5s both;
}

@keyframes scale {
  50% {
    transform: scale(0.5);
  }
  100% {
    transform: scale(1);
  }
}

Mudar a visibilidade de um elemento

Para mostrar ou ocultar um elemento, use opacity.

.animate {
  animation: opacity 2.5s both;
}

@keyframes opacity {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

Evite propriedades que acionam layout ou pintura

Antes de usar qualquer propriedade CSS para animação (exceto transform e opacity), determine o impacto da propriedade no pipeline de renderização. Evite qualquer propriedade que acione layout ou pintura, a menos que seja absolutamente necessário.

Forçar a criação de camadas

Como explicado em Por que algumas animações são lentas?, colocar elementos em uma nova camada permite que o navegador os repinte sem precisar repintar o restante do layout.

Os navegadores geralmente tomam boas decisões sobre quais itens devem ser colocados em uma nova camada, mas é possível forçar manualmente a criação de camadas com a propriedade will-change. Como o nome sugere, essa propriedade informa ao navegador que esse elemento será alterado de alguma forma.

No CSS, é possível aplicar will-change a qualquer seletor:

body > .sidebar {
  will-change: transform;
}

No entanto, a especificação sugere que você só adicione isso a elementos que estão sempre prestes a mudar. Por exemplo, isso pode ser usado para uma barra lateral que o usuário pode deslizar para dentro e para fora. Se o elemento não mudar com frequência, aplique will-change usando JavaScript quando uma mudança for provável. Dê ao navegador tempo suficiente para realizar as otimizações necessárias e remova a propriedade quando a mudança for concluída.

Para forçar a criação de camadas em um navegador sem suporte para will-change, defina transform: translateZ(0).

Depurar animações lentas ou com falhas

O Chrome DevTools e o Firefox DevTools podem ajudar a descobrir por que as animações estão lentas ou com falhas.

Verificar se uma animação aciona o layout

Uma animação que move um elemento usando algo diferente de transform provavelmente será lenta. O exemplo a seguir compara uma animação que usa transform com uma que usa top e left.

O que não fazer
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     top: calc(90vh - 160px);
     left: calc(90vw - 200px);
  }
}
O que fazer
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     transform: translate(calc(90vw - 200px), calc(90vh - 160px));
  }
}

Você pode testar isso nos dois exemplos a seguir e analisar o desempenho usando o DevTools.

Chrome DevTools

  1. Abra o painel Performance.
  2. Registre o desempenho do ambiente de execução enquanto a animação está acontecendo.
  3. Inspecione a guia Resumo.

Se você encontrar um valor diferente de zero para Renderização na guia Resumo, isso pode significar que sua animação está fazendo o navegador realizar o trabalho de layout.

O painel "Resumo" mostra 37 ms para renderização e 79 ms para pintura.
O exemplo de animação com top-left causa trabalho de renderização.
O painel "Summary" mostra valores zero para renderização e pintura.
O exemplo de animação com transformação não causa trabalho de renderização.

Firefox DevTools

No Firefox DevTools, o Waterfall pode ajudar você a entender onde o navegador está gastando tempo.

  1. Abra o painel Performance.
  2. Comece a gravar o desempenho enquanto a animação está acontecendo.
  3. Interrompa a gravação e inspecione a guia Waterfall.

Se você encontrar entradas para Recalculate Style, isso significa que o navegador precisa retornar ao início da cascata de renderização para renderizar a animação.

Verificar se há frames descartados

  1. Abra a guia Renderização no Chrome DevTools.
  2. Marque a caixa de seleção Medidor de QPS.
  3. Observe os valores enquanto a animação é executada.

Preste atenção ao rótulo Frames na parte de cima da interface do medidor de QPS. Isso mostra valores como 50% 1 (938 m) dropped of 1878. Uma animação de alto desempenho tem uma porcentagem alta, como 99%, o que significa que poucos frames estão sendo descartados e a animação parece suave.

O medidor de QPS mostra que 50% dos frames foram descartados
O exemplo de animação com o canto superior esquerdo faz com que 50% dos frames sejam descartados.
O medidor de QPS mostra que apenas 1% dos frames foram descartados
O exemplo de animação com transformação faz com que apenas 1% dos frames sejam descartados.

Verificar se uma animação aciona a pintura

Algumas propriedades são mais caras para o navegador pintar do que outras. Por exemplo, qualquer coisa que envolva um desfoque (como uma sombra, por exemplo) leva mais tempo para ser pintada do que uma caixa vermelha. Essas diferenças nem sempre são óbvias no CSS, mas o DevTools do navegador pode ajudar a identificar quais áreas precisam ser repintadas, além de outros problemas de desempenho relacionados à pintura.

Chrome DevTools

  1. Abra a guia Renderização no Chrome DevTools.
  2. Selecione Piscar pintura.
  3. Mova o ponteiro pela tela.
Um elemento da interface destacado em verde para demonstrar que será redesenhado
Neste exemplo do Google Maps, é possível ver os elementos sendo repintados.

Se você notar que a tela inteira está piscando ou que áreas que não deveriam mudar estão destacadas, investigue mais.

Se você precisar determinar se uma propriedade específica está causando problemas de desempenho relacionados à pintura, o criador de perfil de pintura no Chrome DevTools pode ajudar.

Firefox DevTools

  1. Abra Settings e adicione um botão da caixa de ferramentas para Toggle paint flashing.
  2. Na página que você quer inspecionar, ative o botão e mova o mouse ou role a tela para ver as áreas destacadas.

Animar na fase de composição

Sempre que possível, restrinja as animações a opacity e transform para mantê-las no estágio de composição do caminho de renderização. Use o DevTools para verificar qual estágio do caminho está sendo afetado pelas animações.

Use o criador de perfil de pintura para ver se alguma operação de pintura é particularmente cara. Se você encontrar algo, verifique se uma propriedade CSS diferente oferece a mesma aparência com melhor desempenho.

Use a propriedade will-change com moderação e somente se você encontrar um problema de desempenho.