Animações: @keyframes e animation
2 min de leitura
Transição é "de A para B quando algo mudar". Animação é "rode essa sequência de estados automaticamente, com quantos passos eu quiser, quantas vezes eu quiser". Para coisas como loader, attention-grabbers, entrada de elementos na tela - animação é a ferramenta certa.
@keyframes: definindo a sequência
@keyframes pulsar {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.2); opacity: 0.7; }
100% { transform: scale(1); opacity: 1; }
}
.alerta {
animation: pulsar 1.5s ease-in-out infinite;
}
@keyframes é uma "tabela de estados ao longo do tempo". Você define
percentuais (0%, 50%, 100% são os principais; pode usar qualquer valor
como 17% ou 73%). O navegador interpola entre os estados
declarados.
Shorthand animation
animation: <nome> <duração> <curva> <delay> <contagem> <direção> <fill-mode> <play-state>
Exemplos:
/* Pulsar pra sempre (loader) */
.loader { animation: girar 1s linear infinite; }
/* Uma vez, no carregamento da página */
.aparecer { animation: aparecer 0.3s ease-out 1; }
/* Duas vezes, com delay */
.chamar-atencao { animation: chamar 0.5s ease-in-out 2 0.5s; }
/* duração curva n delay */
/* Piscar só uma vez, sem repetir */
.toast { animation: sumir 4s ease-out 1 forwards; }
Cada parte da shorthand
animation-name: o nome do @keyframes (sem o @).
animation-duration: quanto tempo dura UM ciclo. Padrão: 0s.
animation-timing-function: mesma curva da transition
(ease, linear, cubic-bezier(), etc). Padrão: ease.
animation-delay: espera antes de começar. Útil para escalonar
vários elementos.
animation-iteration-count: quantas vezes repete. Número
(2), ou infinite. Padrão: 1.
animation-direction: a direção do ciclo.
normal(default): 0% → 100%.reverse: 100% → 0%.alternate: 0% → 100% → 0% → 100% (vai e volta). Perfeito para "vai e volta" sem ter que duplicar keyframes.alternate-reverse: começa voltando.
animation-fill-mode: o que acontece antes e depois da
animação. O detalhe que pega muita gente.
none(default): antes e depois, o elemento fica no estado "neutro" (sem efeito da animação).forwards: depois do último ciclo, fica no último keyframe. Essencial para "entrada" - sem isso, o elemento volta pro estado original.backwards: durante o delay, fica no estado do primeiro keyframe.both: forwards + backwards.
.aparecer {
opacity: 0;
transform: translateY(20px);
animation: entrar 0.5s ease-out forwards;
}
@keyframes entrar {
to {
opacity: 1;
transform: translateY(0);
}
}
Sem forwards, o elemento volta a ficar invisível depois da
animação terminar. Com forwards, ele fica visível.
animation-play-state: running ou paused. Pode ser animado
com hover, por exemplo:
.spinner { animation: girar 1s linear infinite; }
.spinner:hover { animation-play-state: paused; }
Animando várias propriedades
Tudo dentro do @keyframes interpola. Você pode animar cor, posição,
opacidade, transform, etc - tudo no mesmo keyframe:
@keyframes aparecer {
0% { opacity: 0; transform: translateY(20px) scale(0.95); }
100% { opacity: 1; transform: translateY(0) scale(1); }
}
Animando propriedade por propriedade (granular)
Para um controle fino, você pode dar durações diferentes:
.modal {
opacity: 0;
transform: scale(0.9);
transition: opacity 0.2s, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.modal.ativo { opacity: 1; transform: scale(1); }
Isso é mistura de transição + classe de estado, não @keyframes, mas muitas vezes é o que você quer. Animação fica para "cenas" autônomas; transição para "feedback" interativo.
Performance
Animações em transform e opacity são baratas (o navegador
acelera por GPU). Em width, height, top, left, margin,
background-position (sem ser cover/contain) - caras (forçam
recalcular layout).
Regra prática: anime o que é "superficial" (posição, escala, rotação, opacidade). Evite animar tamanho ou posição de elementos que afetam o fluxo.
prefers-reduced-motion
De novo (e nunca é demais): respeite. Animações longas, rápidas ou constantes podem ser problemáticas para pessoas com sensibilidade a movimento.
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
@keyframesdefine a sequência.animation: nome dur curva delay n dir filljunta tudo.forwardsmantém o último frame (essencial para entrada).infinitepara loops (loader, atenção).alternatepara "vai e volta" sem duplicar.- Anime
transformeopacity(barato). Evitewidth/height.
Dica: animação boa é sutil. Pulsar 1.2x é legal. Pulsar 1.5x 5 vezes por segundo é irritante. Animação é tempero, não comida - se o usuário percebeu e ficou olhando, é demais.
No próximo nó, vamos mergulhar no transform - a propriedade
responsável por translate, rotate, scale e o mundo 3D que o CSS
permite.