CSS Transitions
Transições suaves entre estados de elementos
CSS Transitions são a base de qualquer interface fluida. Elas permitem que propriedades CSS mudem gradualmente ao longo do tempo, em vez de instantaneamente. Quando um usuário passa o mouse sobre um botão e ele muda de cor suavemente, isso é uma transition. Quando um card ganha sombra ao ser hover, é transition.
A sintaxe básica envolve 4 propriedades: transition-property (qual propriedade animar), transition-duration (quanto tempo), transition-timing-function (curva de aceleração) e transition-delay (tempo de espera).
Para dashboards, transitions são essenciais em hovers de botões, mudanças de estado em cards, expansão de painéis e feedback visual de interações. A regra de ouro: durações entre 150ms e 300ms são percebidas como "rápidas mas suaves".
Propriedades de Transition
all - todas as propriedadesopacity - transparênciatransform - escala, rotação, posiçãobackground-color - cor de fundo150ms - rápida (micro-interações)200ms - padrão recomendado300ms - suave (painéis)500ms+ - lenta (modais)ease - início/fim lentos (padrão)ease-in - início lentoease-out - fim lento (recomendado)linear - velocidade constanteDemonstração de Transitions
Passe o mouse sobre os boxes para ver a diferença de velocidade
/* Transition básica */
.button {
background-color: #3b82f6;
transition: all 200ms ease-out;
}
.button:hover {
background-color: #2563eb;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}
/* Card com múltiplas transitions */
.card {
background: #1f2937;
border: 1px solid #374151;
transition:
transform 200ms ease-out,
box-shadow 300ms ease-out,
border-color 200ms ease-out;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
border-color: #3b82f6;
}
/* Transform origin para efeitos específicos */
.card-expand {
transform-origin: top center;
transition: transform 300ms ease-out;
}
.card-expand:hover {
transform: scaleY(1.05);
}
Dica de Performance
Prefira animar apenas transform e opacity. Essas propriedades são otimizadas pelo navegador (GPU accelerated) e não causam reflow. Evite animar width, height, top, left - são custosas para o navegador.
CSS Animations e @keyframes
Animações complexas com controle total sobre cada etapa
Enquanto transitions são para mudanças simples entre dois estados, CSS Animations permitem criar sequências complexas com múltiplos passos. Usando @keyframes, você define cada etapa da animação com precisão.
Animations são perfeitas para loading spinners, pulsações de alerta, animações de entrada em página, e qualquer efeito que precise rodar continuamente ou ter mais de dois estados. Diferente de transitions, podem iniciar automaticamente sem necessidade de hover ou outro trigger.
A sintaxe usa animation-name, animation-duration, animation-iteration-count (quantas vezes repetir), animation-direction e animation-fill-mode.
Propriedades de Animation
1 - uma vez3 - três vezesinfinite - loop eternonormal - 0% → 100%reverse - 100% → 0%alternate - vai e voltanone - volta ao originalforwards - mantém estado finalbackwards - aplica estado inicialrunning - animação ativapaused - animação pausadaAnimações em Ação
/* Spinner de loading */
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #374151;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 1s linear infinite;
}
/* Pulse para chamar atenção */
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.notification-badge {
animation: pulse 2s ease-in-out infinite;
}
/* Fade in de entrada */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card-enter {
animation: fadeIn 0.5s ease-out forwards;
}
/* Stagger effect (delay por item) */
.card-enter:nth-child(1) { animation-delay: 0ms; }
.card-enter:nth-child(2) { animation-delay: 100ms; }
.card-enter:nth-child(3) { animation-delay: 200ms; }
.card-enter:nth-child(4) { animation-delay: 300ms; }
✓ Fazer
- • Usar animation-fill-mode: forwards para manter estado final
- • Aplicar delays escalonados para listas (stagger effect)
- • Usar will-change para otimizar animações pesadas
- • Preferir ease-out para animações de entrada
✗ Evitar
- • Animações infinitas em elementos não visíveis
- • Durações muito longas (>1s) para micro-interações
- • Animar propriedades que causam reflow
- • Muitas animações simultâneas (distrai usuário)
Tailwind Transition Utilities
Classes utilitárias para animações sem escrever CSS
Tailwind CSS fornece um sistema completo de classes utilitárias para transitions e animations. Isso permite criar interações fluidas diretamente no HTML, sem necessidade de arquivos CSS separados. As classes seguem a convenção do framework e são altamente composíveis.
As principais categorias são: transition-* para definir quais propriedades animar, duration-* para tempo, ease-* para timing function, e animate-* para animações pré-definidas.
A vantagem do Tailwind é a consistência: todos os desenvolvedores usam os mesmos valores de duração e easing, criando uma experiência uniforme. Além disso, o tree-shaking remove classes não usadas, mantendo o bundle pequeno.
Classes de Transition do Tailwind
transition-none - desativatransition-all - todastransition-colors - corestransition-opacity - opacidadetransition-shadow - sombrastransition-transform - transformsduration-75 - 75msduration-100 - 100msduration-150 - 150msduration-200 - 200ms (padrão)duration-300 - 300msduration-500 - 500msease-linear - linearease-in - aceleraease-out - desaceleraease-in-out - ambosanimate-none - sem animaçãoanimate-spin - rotação infinitaanimate-ping - ping/radaranimate-pulse - pulsaçãoanimate-bounce - pulo<!-- Botão com hover suave -->
<button class="bg-blue-600 hover:bg-blue-500
transition-colors duration-200 ease-out
px-4 py-2 rounded-lg">
Salvar
</button>
<!-- Card com elevação no hover -->
<div class="bg-dark-800 rounded-xl border border-dark-600
hover:border-blue-500 hover:shadow-lg hover:-translate-y-1
transition-all duration-300 ease-out">
Conteúdo do card
</div>
<!-- Spinner de loading -->
<div class="w-8 h-8 border-4 border-dark-600 border-t-blue-500
rounded-full animate-spin">
</div>
<!-- Badge pulsante para notificação -->
<span class="absolute -top-1 -right-1 w-3 h-3
bg-red-500 rounded-full animate-pulse">
</span>
<!-- Menu dropdown com fade -->
<div class="opacity-0 invisible group-hover:opacity-100
group-hover:visible transition-all duration-200">
Menu items
</div>
<!-- Scale no hover -->
<button class="transform hover:scale-105
transition-transform duration-150">
Zoom Button
</button>
Combinação Ideal
Para a maioria dos casos em dashboards, use esta combinação: transition-all duration-200 ease-out. É rápida o suficiente para não parecer lenta, mas suave o suficiente para ser perceptível. Para hovers simples de cor, transition-colors duration-150 é mais performática.
Micro-interações
Feedback visual que torna interfaces vivas e responsivas
Micro-interações são pequenas animações que respondem às ações do usuário, fornecendo feedback imediato. Quando um botão "afunda" ao ser clicado, quando um checkbox anima ao ser marcado, quando um input ganha um brilho ao receber foco - todas são micro-interações.
Em dashboards, micro-interações são cruciais para comunicar que o sistema está respondendo. Sem elas, a interface parece "morta" ou quebrada. O usuário precisa de confirmação visual instantânea de que sua ação foi reconhecida, mesmo que o resultado demore a processar.
Os tipos mais importantes são: hover states (indica que elemento é clicável), active states (feedback de clique), focus states (acessibilidade), loading states (processando), e success/error states (resultado da ação).
Tipos de Micro-interações
Exemplos de Micro-interações
Botão com hover + active
Input com focus ring
Card com elevação
Toggle switch
<!-- Botão com feedback completo -->
<button class="
bg-blue-600 text-white px-4 py-2 rounded-lg font-medium
/* Hover - clarear e elevar */
hover:bg-blue-500 hover:-translate-y-0.5 hover:shadow-lg
/* Active - afundar */
active:translate-y-0 active:scale-[0.98]
/* Focus - ring para acessibilidade */
focus:outline-none focus:ring-2 focus:ring-blue-400
focus:ring-offset-2 focus:ring-offset-dark-800
/* Transition */
transition-all duration-150 ease-out
">
Salvar alterações
</button>
<!-- Like button com animação de coração -->
<button class="group p-2 rounded-full hover:bg-red-500/10
transition-colors duration-200">
<svg class="w-6 h-6 text-neutral-400
group-hover:text-red-500 group-hover:scale-110
group-active:scale-95
transition-all duration-200">
<!-- heart icon -->
</svg>
</button>
<!-- Expandir/Colapsar com rotação de ícone -->
<button class="flex items-center gap-2 group">
<span>Ver detalhes</span>
<svg class="w-4 h-4 transform group-hover:rotate-180
transition-transform duration-200">
<!-- chevron icon -->
</svg>
</button>
Tempos Recomendados
Loading Animations
Spinners, skeletons e indicadores de progresso
Loading animations comunicam ao usuário que algo está acontecendo. São essenciais em dashboards que fazem requisições a APIs, processam dados ou aguardam respostas do servidor. Sem elas, o usuário pensa que a interface travou.
Existem três padrões principais: Spinners para carregamentos curtos e indeterminados (não sabemos quanto vai demorar), Skeleton screens para carregamento de conteúdo estruturado (mostra a "forma" do que virá), e Progress bars para carregamentos determinados (sabemos o progresso exato).
A escolha depende do contexto: spinners são genéricos, skeletons melhoram a percepção de velocidade (usuário "vê" o layout antes do conteúdo), e progress bars são para uploads, downloads ou processos em etapas.
Tipos de Loading Indicators
Skeleton Screen - Card de Usuário
Loading...
Loaded
Desenvolvedor full-stack com 5 anos de experiência em React e Node.js.
<!-- Spinner simples -->
<div class="w-8 h-8 border-4 border-dark-600 border-t-blue-500
rounded-full animate-spin"></div>
<!-- Spinner em botão -->
<button disabled class="bg-blue-600 px-4 py-2 rounded-lg
flex items-center gap-2 opacity-80">
<svg class="w-4 h-4 animate-spin" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" stroke="currentColor"
stroke-width="4" fill="none" opacity="0.25"/>
<path fill="currentColor" d="M4 12a8 8 0 018-8V0C5.4 0 0 5.4 0 12h4z"/>
</svg>
Salvando...
</button>
<!-- Skeleton de texto -->
<div class="space-y-2">
<div class="h-4 bg-dark-600 rounded animate-pulse"></div>
<div class="h-4 bg-dark-600 rounded animate-pulse w-3/4"></div>
<div class="h-4 bg-dark-600 rounded animate-pulse w-5/6"></div>
</div>
<!-- Skeleton de avatar + texto -->
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-dark-600 rounded-full animate-pulse"></div>
<div class="space-y-2 flex-1">
<div class="h-4 bg-dark-600 rounded animate-pulse w-1/2"></div>
<div class="h-3 bg-dark-600 rounded animate-pulse w-1/3"></div>
</div>
</div>
<!-- Progress bar -->
<div class="w-full bg-dark-600 rounded-full h-2 overflow-hidden">
<div class="bg-blue-500 h-full rounded-full transition-all duration-300"
style="width: 67%"></div>
</div>
<!-- Indeterminate progress (animação infinita) -->
<div class="w-full bg-dark-600 rounded-full h-1 overflow-hidden">
<div class="bg-blue-500 h-full w-1/3 animate-[shimmer_1s_infinite]"></div>
</div>
<style>
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(400%); }
}
</style>
✓ Fazer
- • Usar skeleton que reflete layout real do conteúdo
- • Mostrar loading imediatamente (< 100ms)
- • Desabilitar botões durante loading
- • Usar spinner DENTRO do botão que disparou a ação
✗ Evitar
- • Loading overlay cobrindo toda a tela
- • Não mostrar nada durante carregamento
- • Skeleton genérico que não representa o conteúdo
- • Spinners em toda parte (um por vez é suficiente)
Animações de Entrada e Saída
Fade, slide, scale e transições de página
Animações de entrada e saída controlam como elementos aparecem e desaparecem da interface. São fundamentais para modais, dropdowns, toasts, notificações e transições de página. Um elemento que simplesmente "aparece" é abrupto; um que faz fade-in parece natural.
Os três padrões mais usados são: Fade (mudança de opacidade), Slide (movimento de posição) e Scale (mudança de tamanho). Frequentemente são combinados: fade+slide para notificações, fade+scale para modais.
A regra importante é: entradas devem ser mais rápidas que saídas. O usuário quer ver o novo conteúdo rapidamente, mas a saída pode ser mais lenta para não parecer que algo "sumiu". Timing típico: entrada 200-300ms, saída 150-200ms.
Padrões de Animação
Demonstração de Animações
Recarregue a página para ver as animações novamente
/* FADE IN */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.animate-fadeIn {
animation: fadeIn 0.3s ease-out forwards;
}
/* SLIDE UP (para toasts, modais) */
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-slideUp {
animation: slideUp 0.4s ease-out forwards;
}
/* SCALE IN (para modais, cards) */
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
.animate-scaleIn {
animation: scaleIn 0.2s ease-out forwards;
}
/* SLIDE FROM RIGHT (para sidebars) */
@keyframes slideRight {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
/* COMBINAÇÃO: Fade + Scale para modal */
.modal-enter {
animation: fadeIn 0.2s ease-out, scaleIn 0.2s ease-out;
}
/* SAÍDA: geralmente mais rápida */
.modal-leave {
animation: fadeIn 0.15s ease-in reverse forwards,
scaleIn 0.15s ease-in reverse forwards;
}
<!-- Modal container -->
<div id="modal" class="fixed inset-0 z-50 hidden">
<!-- Backdrop com fade -->
<div class="absolute inset-0 bg-black/60
opacity-0 transition-opacity duration-200"
id="backdrop"></div>
<!-- Modal content com scale + fade -->
<div class="absolute inset-0 flex items-center justify-center p-4">
<div class="bg-dark-800 rounded-xl max-w-md w-full p-6
opacity-0 scale-95
transition-all duration-200"
id="modal-content">
<h3 class="text-xl font-bold mb-4">Título do Modal</h3>
<p class="text-neutral-400 mb-6">Conteúdo do modal aqui.</p>
<button onclick="closeModal()"
class="bg-blue-600 px-4 py-2 rounded-lg">
Fechar
</button>
</div>
</div>
</div>
<script>
function openModal() {
const modal = document.getElementById('modal');
const backdrop = document.getElementById('backdrop');
const content = document.getElementById('modal-content');
modal.classList.remove('hidden');
// Trigger animations (next frame)
requestAnimationFrame(() => {
backdrop.classList.add('opacity-100');
content.classList.remove('opacity-0', 'scale-95');
content.classList.add('opacity-100', 'scale-100');
});
}
function closeModal() {
const modal = document.getElementById('modal');
const backdrop = document.getElementById('backdrop');
const content = document.getElementById('modal-content');
// Animate out
backdrop.classList.remove('opacity-100');
content.classList.remove('opacity-100', 'scale-100');
content.classList.add('opacity-0', 'scale-95');
// Hide after animation
setTimeout(() => modal.classList.add('hidden'), 200);
}
</script>
Stagger Effect para Listas
Quando múltiplos elementos entram juntos (cards de dashboard, itens de lista), use delays escalonados. Cada item tem 50-100ms a mais de delay que o anterior. Isso cria um efeito de "cascata" que é mais agradável que todos aparecerem juntos. Em Tailwind: delay-[100ms], delay-[200ms], etc.
Resumo de Timings
| Tipo | Entrada | Saída | Easing |
|---|---|---|---|
| Modal | 200-300ms | 150-200ms | ease-out |
| Toast | 300ms | 200ms | ease-out |
| Dropdown | 150ms | 100ms | ease-out |
| Sidebar | 300ms | 250ms | ease-in-out |
📋 Resumo do Módulo
O que você aprendeu:
- ✓ CSS Transitions para mudanças suaves entre estados
- ✓ @keyframes para animações complexas e contínuas
- ✓ Classes utilitárias do Tailwind para transitions
- ✓ Micro-interações para feedback visual imediato
- ✓ Loading indicators: spinners, skeletons, progress
- ✓ Animações de entrada e saída para modais e overlays
Regras de ouro:
- ⚡ Durações: 150-300ms para a maioria das interações
- ⚡ Performance: prefira transform e opacity
- ⚡ Entrada > Saída: entradas mais lentas, saídas mais rápidas
- ⚡ Easing: ease-out para entradas, ease-in para saídas
- ⚡ Menos é mais: animações demais distraem o usuário
Animações bem aplicadas fazem a diferença entre uma interface "funcional" e uma interface "profissional". Use com intenção!