Animação Web
Bom movimento na web é uma decisão de design primeiro e uma chamada de biblioteca em segundo. Siga o fluxo de trabalho abaixo em ordem; carregue os arquivos de regras apenas quando uma etapa precisar deles.
Fluxo de Trabalho
1. Leia o projeto antes de escolher qualquer coisa
- Verifique o
package.json. Se uma biblioteca de animação já estiver instalada, use-a. Não adicione uma segunda para um único efeito. - Anote o framework (React / Next.js App Router / Vue / Svelte / HTML puro) e se os componentes renderizam no servidor (
"use client"é necessário para animações no lado do cliente no Next.js). - Verifique se existem tokens de movimento (durações, easing) em variáveis CSS ou em um arquivo de tema e reutilize-os.
2. Decida para que serve o movimento
Cada animação precisa de um trabalho. Escolha um por elemento:
| Trabalho | Exemplo | Orçamento típico |
|---|---|---|
| Feedback — confirma uma ação | pressionar botão, alternar, copiar para área de transferência | 100–200ms |
| Orientação — mostra de onde algo veio ou para onde foi | modal abre a partir do seu gatilho, reordenação de item de lista, mudança de rota | 200–400ms |
| Atenção — aponta para uma coisa | uma única sequência de herói, uma nova notificação | 400–1200ms, uma vez |
| Narrativa — conta uma história vinculada ao scroll | tour de produto fixo, linha do tempo controlada | vinculado à distância de scroll |
Se um elemento não tem trabalho, não o anime. Um momento orquestrado vence um fade-up em cada seção. Leia rules/motion-design.md para durações, easing, coreografia e a lista de verificação de "sensação premium".
3. Escolha a ferramenta mais leve que faz o trabalho
Plataforma primeiro, depois bibliotecas:
| Necessidade | Alcance para | Arquivo de regra |
|---|---|---|
| Hover, foco, press, loops simples | Transições CSS / @keyframes | css-keyframes.md |
| Entrada e saída de diálogo, popover, dropdown | @starting-style CSS + transition-behavior: allow-discrete | css-keyframes.md |
| Transições de página / rota, morph de elemento compartilhado entre estados | View Transitions API | view-transitions.md |
| Revelação simples vinculada a scroll, barra de progresso, parallax | CSS animation-timeline: view() / scroll() | scroll-animations.md |
| Seções fixas, linhas do tempo de múltiplas etapas controladas, scroll horizontal | GSAP + ScrollTrigger | gsap.md |
| Revelações de título com texto dividido / máscara de linha | GSAP SplitText | gsap.md |
| Animação de entrada/saída no React, layout e layout compartilhado, gestos | Motion for React (motion/react) | framer-motion.md |
| Animação imperativa sem framework, molas | Motion (motion) | motion-one.md |
| Desenho de linha SVG e morph sem GSAP | Anime.js v4 (svg.createDrawable, svg.morphTo) | animejs.md |
| Morph de caminho complexo entre formas não relacionadas | Flubber (ou GSAP MorphSVG) | flubber.md |
| Reprodução de animação do After Effects | Lottie (dotLottie) | lottie.md |
| Animação ilustrada interativa e orientada a estado | Rive | rive.md |
| Gráficos animados | Transições D3 | d3.md |
| Muitas formas 2D interativas (editores, diagramas) | Konva | konva.md |
| 3D, partículas, shaders | Three.js / React Three Fiber | three-js.md |
Quando a escolha não for óbvia, leia rules/choosing-library.md.
4. Construa com os não negociáveis
Isso se aplica a toda animação, em toda biblioteca:
- Anime
transformeopacity. Evite animarwidth,height,top,left,margin; usescale/translate, FLIP (GSAP Flip, Motionlayout) ou View Transitions para mudanças de layout. Veja rules/performance.md. - Respeite
prefers-reduced-motion. Substitua movimento por um fade de opacidade ou uma mudança instantânea; nunca apenas delete a entrada do conteúdo para que ele permaneça invisível. Efeitos controlados por scroll devem se tornar estáticos. - Nunca esconda o conteúdo até o JS executar. Defina o estado inicial oculto em JS (ou atrás de uma classe
.js), para que o conteúdo fique visível se o script falhar. Com SSR, evite um flash de conteúdo visível-depois-oculto aplicando estilos iniciais antes da primeira pintura. - Faça a limpeza. Reverta ou mate animações ao desmontar (
useGSAP,createScope().revert(),gsap.context), e mate ScrollTriggers na mudança de rota. - Mantenha a interação responsiva. Animações interrompíveis para qualquer coisa acionada pelo usuário: um segundo clique não deve enfileirar atrás do primeiro. Nunca bloqueie a entrada esperando uma animação terminar.
- Não anime o foco para longe. Elementos que se movem devem manter um estado
:focus-visiblevisível, e diálogos animados ainda devem mover o foco corretamente.
5. Verifique em um navegador real
Não relate uma animação como concluída apenas lendo o código. Execute-a e verifique:
- Ela é reproduzida e o estado final corresponde ao design (captura de tela no meio da animação e em repouso).
- Nenhum erro no console, nenhuma mudança de layout quando inicia.
- Emule
prefers-reduced-motion: reducee confirme se a versão reduzida funciona e o conteúdo está visível. - Redimensione para uma largura de celular: seções fixas e texto dividido ainda funcionam (re-dividir ao redimensionar).
- Efeitos acionados por scroll funcionam ao rolar para cima e para baixo, e após um recarregamento no meio da página.
- Painel de desempenho: sem quadros longos durante a animação, sem picos de layout/pintura de propriedades animadas.
Pontos de partida mínimos
// GSAP + ScrollTrigger (npm i gsap)
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
gsap.from(".card", {
y: 40, opacity: 0, duration: 0.8, ease: "expo.out", stagger: 0.08,
scrollTrigger: { trigger: ".cards", start: "top 80%" },
});
// Motion for React (npm i motion)
import { motion, AnimatePresence } from "motion/react";
<AnimatePresence>
{open && (
<motion.div
key="painel"
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 8 }}
transition={{ type: "spring", duration: 0.35, bounce: 0 }}
/>
)}
</AnimatePresence>
/* Revelação de scroll apenas com plataforma: Chrome 115+, Safari 26+, Firefox 159+ */
@media (prefers-reduced-motion: no-preference) {
@supports (animation-timeline: view()) {
.reveal {
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 10% cover 30%;
}
}
}
@keyframes reveal { from { opacity: 0; translate: 0 2rem; } }
Arquivos de regra
- rules/motion-design.md — durações, easing, coreografia, o que faz o movimento parecer premium
- rules/choosing-library.md — fluxo de decisão, matriz de capacidade, tamanhos de bundle medidos
- rules/performance.md — propriedades apenas do compositor, perfilamento,
will-change, movimento reduzido - rules/scroll-animations.md — linhas do tempo de scroll CSS, padrões ScrollTrigger, scroll suave
- rules/view-transitions.md — transições de página no mesmo documento e entre documentos
- rules/css-keyframes.md — transições,
@keyframes,@starting-style, easinglinear() - rules/gsap.md — timelines, ScrollTrigger, SplitText, Flip,
useGSAP - rules/framer-motion.md — Motion para React: variantes,
AnimatePresence, layout, gestos - rules/motion-one.md — Motion vanilla JS:
animate, sequências,scroll,inView - rules/animejs.md — Anime.js v4: timelines, stagger, desenho e morph SVG
- rules/lottie.md — player dotLottie, controles, eventos
- rules/rive.md — máquinas de estado e entradas
- rules/d3.md — transições de data-join
- rules/flubber.md — morph de caminho
- rules/konva.md — formas 2D e tweens em canvas
- rules/three-js.md — cenas, R3F, desempenho
Exemplos funcionais dessas técnicas estão em demos/.