Animações Profissionais com @keyframes no CSS | Web Academy
Na lição anterior, você aprendeu que as transições são perfeitas para suavizar a passagem entre dois estados quando o usuário interage com a página. No entanto, muitas interfaces exigem experiências cinematográficas contínuas: indicadores de carregamento que giram sem parar, notificações que entram suavemente na tela assim que o documento abre, ou ilustrações que flutuam em ciclos infinitos de respiração. Para coreografar múltiplos estágios temporais sem depender de ações do mouse, o CSS nos entrega o poderoso motor de @keyframes e a propriedade animation.
📑 Índice do Conteúdo
1. A Linha do Tempo: Criando Regras com @keyframes
Uma animação em CSS é dividida em duas partes: a linha do tempo (Timeline), declarada com a regra-arroba @keyframes, e a aplicação da animação, configurada no seletor do elemento.
/* 1. DEFINIÇÃO DA LINHA DO TEMPO */
@keyframes pulsarBrilho {
0% {
transform: scale(1);
opacity: 0.6;
}
50% {
transform: scale(1.12);
opacity: 1;
}
100% {
transform: scale(1);
opacity: 0.6;
}
}
/* 2. APLICAÇÃO NO ELEMENTO */
.badge-alerta {
animation: pulsarBrilho 2s ease-in-out infinite;
}
Você pode usar as palavras-chave from (equivalente a 0%) e to (equivalente a 100%) para animações simples, ou declarar quantos marcos percentuais intermediários desejar (0%, 25%, 60%, 100%) para coreografias ricas.
2. As 8 Subpropriedades do animation
A propriedade abreviada animation encapsula 8 controles cirúrgicos:
| Propriedade | Valores Principais | Função na Animação |
|---|---|---|
animation-name |
Nome da regra @keyframes |
Conecta o elemento à sua linha do tempo. |
animation-duration |
Tempo (ex.: 1.5s, 400ms) |
Duração de exatamente 1 ciclo da animação. |
animation-timing-function |
ease, linear, cubic-bezier, steps() |
Curva de aceleração do movimento. |
animation-delay |
Tempo positivo ou negativo (ex.: -0.5s) |
Tempo de espera antes do início do primeiro ciclo. |
animation-iteration-count |
Número inteiro ou infinite |
Quantas vezes a animação repetirá o ciclo. |
animation-direction |
normal, reverse, alternate |
alternate cria o efeito de ping-pong (vai e volta suavemente). |
animation-fill-mode |
none, forwards, backwards, both |
Controla como os estilos persistem antes e após a execução. |
animation-play-state |
running, paused |
Permite pausar ou retomar a animação (ex.: no :hover). |
3. animation-fill-mode: O Fim dos Saltos Bruscos
O maior pesadelo dos iniciantes é animar um card surgindo de baixo para cima com fade-in: a animação roda lindamente e, no instante em que chega a 100%, o card desaparece ou salta bruscamente de volta para o estado inicial!
Isso acontece porque, por padrão (animation-fill-mode: none), o navegador descarta todos os estilos do @keyframes assim que a animação termina.
A Solução Definitiva com forwards e both:
forwards: Ordena ao navegador que mantenha permanentemente os estilos do último frame (100%) na tela após o término. O elemento nunca mais salta de volta!backwards: Aplica os estilos do primeiro frame (0%) durante o período doanimation-delay(evita que o elemento apareça antes da hora).both: O padrão ouro! Aplica tantoforwardsquantobackwards, garantindo entradas de tela impecáveis.
/* Animação de Entrada Perfeita e Sem Saltos */
.card-entrada {
animation: deslizarParaCima 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes deslizarParaCima {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
4. Pausando Loops no Hover: animation-play-state
Se você tem uma fita de marcas correndo na tela (marquee infinito) ou um disco girando, o usuário pode querer pausar a animação para ler com calma ao passar o mouse:
.disco-giratorio {
animation: girar 8s linear infinite;
}
.disco-giratorio:hover {
animation-play-state: paused; /* Congela o giro exatamente no frame atual! */
}
5. Animações em Degraus com steps(): O Efeito Máquina de Escrever
Em vez de uma transição fluida e suave, a função steps(n) quebra a interpolação em um número fixo de “degraus” discretos. É a base para animar spritesheets de jogos retrô e criar o efeito de digitação mecânica (Typewriter):
.texto-maquina {
overflow: hidden;
white-space: nowrap;
width: 22ch; /* Largura exata de 22 caracteres */
animation: digitar 3s steps(22) infinite alternate;
}
@keyframes digitar {
from { width: 0; }
to { width: 22ch; }
}
6. Acessibilidade e Performance Gráfica (WCAG 2.2)
Blindagem de Performance e Saúde:
- Performance: Anime preferencialmente
transformeopacity. Evite animarwidth,height,topoumarginem loops infinitos, sob pena de travar a CPU e descarregar baterias de celulares. - Acessibilidade: Elementos piscantes ou que se movem continuamente podem desencadear convulsões ou tonturas severas. É obrigatório incluir:
@media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; } }
7. Laboratório Prático: 3 Animações de Produção em Ação
No código interativo abaixo, construímos três animações do mundo real: um Spinner de Carregamento Infinito, um Efeito Máquina de Escrever com Cursor Piscante e um Card com Entrada Suave (Fade & Slide) usando animation-fill-mode: both:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Laboratório de Animações @keyframes CSS</title>
<style>
body {
font-family: 'Inter', system-ui, sans-serif;
background: #0b0f19;
color: #f8fafc;
padding: 40px;
margin: 0;
}
.painel-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 24px;
margin-top: 24px;
}
.card-animacao {
background: #1e293b;
border: 1px solid #334155;
border-radius: 14px;
padding: 24px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 200px;
text-align: center;
}
/* 1. SPINNER DE CARREGAMENTO (LOOP INFINITO) */
.spinner-radar {
width: 48px;
height: 48px;
border: 4px solid #334155;
border-top-color: #38bdf8;
border-radius: 50%;
animation: girar 1s linear infinite;
}
@keyframes girar {
to { transform: rotate(360deg); }
}
/* 2. EFEITO TYPEWRITER COM STEPS() */
.typewriter-box {
display: inline-block;
font-family: monospace;
font-size: 1.1rem;
color: #10b981;
white-space: nowrap;
overflow: hidden;
border-right: 3px solid #10b981;
width: 17ch; /* 17 caracteres */
animation:
escrever 3.5s steps(17) infinite alternate,
piscarCursor 0.7s step-end infinite;
}
@keyframes escrever {
from { width: 0; }
to { width: 17ch; }
}
@keyframes piscarCursor {
50% { border-color: transparent; }
}
/* 3. CARD COM ENTRADA CINEMATOGRÁFICA (FILL-MODE: BOTH) */
.card-entrada-suave {
animation: surgirComFade 1s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes surgirComFade {
0% {
opacity: 0;
transform: translateY(24px) scale(0.95);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
</style>
</head>
<body>
<h2 style="color:#f1f5f9; margin-top:0;">Animações Avançadas com @keyframes</h2>
<p style="color:#94a3b8; font-size:0.9rem;">
Observe três cenários de produção controlados exclusivamente pelo motor gráfico do CSS:
</p>
<div class="painel-grid">
<div class="card-animacao">
<div class="spinner-radar"></div>
<p style="margin:16px 0 0 0; color:#94a3b8; font-size:0.85rem;">Spinner Infinito (linear infinite)</p>
</div>
<div class="card-animacao">
<div class="typewriter-box">Web-ZoneWare 2026</div>
<p style="margin:16px 0 0 0; color:#94a3b8; font-size:0.85rem;">Typewriter com <code>steps()</code></p>
</div>
<div class="card-animacao card-entrada-suave">
<h4 style="margin:0 0 8px 0; color:#38bdf8;">Entrada Blindada</h4>
<p style="margin:0; font-size:0.85rem; color:#94a3b8;">Retém o estado com <code>animation-fill-mode: both</code></p>
</div>
</div>
</body>
</html>
Abra este laboratório no Playground IDE e teste alterar a curva de aceleração ou a direção da animação para alternate para comprovar a versatilidade do @keyframes:
8. Resumo e Próximos Passos
@keyframesdefine uma linha do tempo autônoma através de porcentagens (0%a100%).- A propriedade
animationconecta o elemento à timeline e dita duração, repetições e velocidade. animation-fill-mode: forwardsoubothimpede que a animação sofra saltos bruscos ao terminar.animation-direction: alternatecria loops suaves de ida e volta (ping-pong).- A função
steps()divide a interpolação em degraus rígidos, ideal para sprites e efeitos de digitação. - Priorize animar
transformeopacitypara manter 60fps acelerados pela placa de vídeo.
Próximo Passo: Como organizar paletas de cores globais, alternar entre Modo Claro e Escuro dinamicamente e evitar valores mágicos repetidos no CSS? Na Lição 45, desvendaremos as CSS Variables (Custom Properties) & Dark Mode Dinâmico!