CSS x JavaScript • Josh W. Comeau

Uma das dúvidas mais comuns sobre o desempenho da animação é se as animações baseadas em JS são mais lentas do que as baseadas em CSS. Devemos sempre nos esforçar para usar transições CSS ou podemos usar bibliotecas de animação JavaScript?
Há uma quantidade surpreendente de nuances nesta questão, e acho que a sabedoria convencional não está muito certa. Neste post, vamos nos aprofundar nessa questão e ver as diferenças por nós mesmos!
Link para este títuloComparando quadros-chave CSS com loops JavaScript
Suponhamos que estamos construindo a seguinte animação:
Podemos conectar isso com um quadro-chave CSS, assim:
@keyframes bounce {
to {
transform: translateX(calc(var(--bounce-magnitude) * -1));
}
}
.ball {
--bounce-magnitude: 200px;
animation: bounce 1000ms infinite alternate;
}
(Estou usando uma transformação CSS para esta animação porque ela produz o movimento mais suave. Nos casos em que o tamanho do contêiner é dinâmico, precisaríamos calcular e aplicar --bounce-magnitude em JS.)
Alternativamente, poderíamos implementar esta animação usando JavaScript! Antes de considerarmos bibliotecas JS como GSAP ou Motion, vamos começar com uma versão JS simples:
const startTime = performance.now();
const ball = document.querySelector('.ball');
function animate() {
const elapsedTime = performance.now() - startTime;
// ✂️ Calculate `x` based on the amount of time that has passed.
ball.style.transform = `translateX(${x}px)`;
window.requestAnimationFrame(animate);
}
Este código usa requestAnimationFrame para executar o animate funciona em cada quadro (60 vezes por segundo na maioria dos monitores). Cortei a lógica principal para calcular x já que é um pouco complicado e não relevante para o tópico em questão, mas você pode ver o completo código(abre em nova aba) se você está curioso.
Aqui está a pergunta: qual abordagem você acha que funciona melhor?
Acho que para a maioria de nós, nossas intuições nos diriam que a versão CSS tem melhor desempenho. E a nossa intuição está correta, mas talvez não pelas razões que pensamos. 😅
Você pode pensar que a versão JS é mais lenta porque precisa fazer todo aquele trabalho extra calculando o x valor em cada quadro ou que há um custo extra para “cruzar a ponte” entre JavaScript e DOM. Mas os mecanismos de navegador modernos podem lidar com tudo isso sem suar a camisa; mesmo em dispositivos de baixo custo, esse trabalho acontece em uma pequena fração de milissegundo, rápido demais para afetar a taxa de quadros de nossa animação.
Mas há uma diferença significativa: a versão JavaScript é executada no thread principal, junto com todo o resto acontecendo em nossa aplicação. As transições CSS e as animações de quadros-chave são executadas em um thread separado, para que não sejam interrompidas quando algo acontece em JavaScript.
Tomei a liberdade de criar uma simulação. Clique no botão “Play” para executar a demonstração. A cada poucos segundos, o thread principal será bloqueado. Observe o efeito que isso tem nessas duas animações:
Em aplicações web modernas, o thread principal faz bastante de trabalho. Estruturas JavaScript como React estão constantemente fazendo atualizações no DOM, para mantê-lo sincronizado com o estado do aplicativo. Cada vez que fazemos um fetch solicitação (por exemplo, para carregar mais dados ou para atualizar dados existentes), essa resposta deve ser analisada pelo thread principal.
Então, se você já viu um botão giratório congelar por um momento antes de a IU ser atualizada, é por isso! As animações baseadas em JavaScript precisam competir pelo poder de processamento com o restante do aplicativo.
No exemplo acima, usei um requestAnimationFrame loop para atualizar a IU em cada quadro em JavaScript. Esta é uma técnica de nível bastante baixo; na prática, muitos desenvolvedores usam bibliotecas JavaScript que fornecem uma abstração de nível superior.
Vamos comparar duas bibliotecas de animação populares, Movimento(abre em nova aba) (anteriormente Framer Motion) e GSAP(abre em nova aba):
Huh! Tanto o Motion quanto o GSAP são baseados em JavaScript, então você pode esperar que eles compartilhem as mesmas limitações de execução no thread principal. Mas de alguma forma, o Motion consegue manter a animação funcionando perfeitamente mesmo quando o thread principal está ocupado. 🤔
O segredo é que o Motion usa as animações da Web API(abre em nova aba) (WAAPI) nos bastidores. WAAPI é essencialmente uma interface JavaScript que se conecta ao mesmo mecanismo de animação de baixo nível das animações de quadro-chave CSS. Assim, o Motion é capaz de executar suas animações em um thread separado, evitando a principal armadilha da maioria das outras bibliotecas de animação JavaScript! 😮
Para ser justo com o GSAP, é uma biblioteca extremamente poderosa que inclui recursos que provavelmente não são compatíveis com WAAPI. Portanto, não é que a GSAP tenha feito a escolha errada, é que estão a escolher diferentes compromissos.
Em meu próprio trabalho, tento usar animações/transições CSS nativas sempre que posso. Quando me deparo com situações que o CSS sozinho não consegue resolver, tento usar uma biblioteca como Motion, que resolve o problema sem as desvantagens normalmente associadas às bibliotecas JS.
Dito isto, o CSS tornou-se tão poderoso que realmente não há que muitos casos em que hoje em dia precisamos recorrer a uma biblioteca de animação; novas APIs como View Transitions, linear() e Animation Timeline tornam possível fazer todo tipo de coisa sem JavaScript. ✨
Exploramos todas essas ferramentas e muito mais em meu novo curso, Whimsical Animações(abre em nova aba). Mostrarei como projeto e implemento animações de alto nível usando CSS, JavaScript, SVG e Canvas modernos.

Hoje em dia, os LLMs são ótimos para gerar sintaxe, mas ainda precisamos usar nosso próprio julgamento. Nesta postagem do blog, aprendemos sobre as considerações de desempenho entre CSS e JavaScript, e meu curso está cheio de coisas como esta. Portanto, independentemente de você estar escrevendo código manualmente ou não, este curso o ajudará a criar animações e interações impressionantes.
Você pode aprender mais sobre isso aqui:
Última atualização em
3 de junho de 2026






