Início Trilha 2 Módulo 2.7
MÓDULO 2.7

✨ Animações e Transições

Micro-interações, feedback visual e animações que tornam dashboards mais fluidos e intuitivos.

6
Tópicos
45min
Duração
Inter.
Nível
Prático
Tipo
1
🔄

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

transition-property
O que animar
all - todas as propriedades
opacity - transparência
transform - escala, rotação, posição
background-color - cor de fundo
transition-duration
Duração da animação
150ms - rápida (micro-interações)
200ms - padrão recomendado
300ms - suave (painéis)
500ms+ - lenta (modais)
transition-timing-function
Curva de aceleração
ease - início/fim lentos (padrão)
ease-in - início lento
ease-out - fim lento (recomendado)
linear - velocidade constante
Shorthand
Forma abreviada
transition: all 200ms ease-out;
property duration timing delay

Demonstração de Transitions

150ms
Rápida
300ms
Suave
500ms
Lenta

Passe o mouse sobre os boxes para ver a diferença de velocidade

CSS Transitions styles.css
/* 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.

2
🎬

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

animation-iteration-count
Quantas vezes repetir
1 - uma vez
3 - três vezes
infinite - loop eterno
animation-direction
Direção da animação
normal - 0% → 100%
reverse - 100% → 0%
alternate - vai e volta
animation-fill-mode
Estado final/inicial
none - volta ao original
forwards - mantém estado final
backwards - aplica estado inicial
animation-play-state
Controle de play/pause
running - animação ativa
paused - animação pausada

Animações em Ação

Spin
Pulse
Bounce
Ping
@keyframes Animations animations.css
/* 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)
3
🎨

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-*
Propriedades a animar
transition-none - desativa
transition-all - todas
transition-colors - cores
transition-opacity - opacidade
transition-shadow - sombras
transition-transform - transforms
duration-*
Duração em ms
duration-75 - 75ms
duration-100 - 100ms
duration-150 - 150ms
duration-200 - 200ms (padrão)
duration-300 - 300ms
duration-500 - 500ms
ease-*
Timing function
ease-linear - linear
ease-in - acelera
ease-out - desacelera
ease-in-out - ambos
animate-*
Animações prontas
animate-none - sem animação
animate-spin - rotação infinita
animate-ping - ping/radar
animate-pulse - pulsação
animate-bounce - pulo
Tailwind Transitions component.html
<!-- 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.

4
👆

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

Hover State
Feedback de "clicável"
• Mudança de cor (lighten/darken)
• Elevação (shadow + translateY)
• Underline em links
• Reveal de ícone ou texto
Active State
Feedback de clique
• Scale down (95-98%)
• Afundar (translateY positivo)
• Escurecer levemente
• Ring pulsante
Focus State
Indicador de foco (a11y)
• Ring outline colorido
• Border highlight
• Glow/shadow suave
• Importante para navegação por teclado
Toggle/Switch
Mudança de estado
• Slide horizontal (switch)
• Checkmark aparecer
• Mudança de cor
• Rotação de ícone

Exemplos de Micro-interações

Botão com hover + active

Input com focus ring

Card com elevação

Card Item
Passe o mouse

Toggle switch

Micro-interações em Tailwind buttons.html
<!-- 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

50-100ms
Hover color
100-150ms
Button press
200-300ms
Card elevation
300-500ms
Panel expand
5

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

Spinner
Indeterminado, genérico
Uso: botões, modais, fetching
Skeleton
Placeholder animado
Uso: listas, cards, texto
Progress Bar
Determinado, percentual
67%
Uso: uploads, processos

Skeleton Screen - Card de Usuário

Loading...

Loaded

JD
John Doe
john@example.com

Desenvolvedor full-stack com 5 anos de experiência em React e Node.js.

Loading Components loading.html
<!-- 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)
6
🚀

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

Fade
Opacidade 0 → 1
• Mais sutil e universal
• Bom para overlays, tooltips
• Funciona em qualquer direção
• opacity: 0 → opacity: 1
Slide
Movimento de posição
• Indica origem do elemento
• Slide-up para toasts/modais
• Slide-right para sidebars
• translateY/translateX
Scale
Mudança de tamanho
• Efeito de "pop" ou "zoom"
• scale: 0.9 → scale: 1
• Bom para modais e cards
• Combinado com fade

Demonstração de Animações

👻
Fade In
⬆️
Slide Up
💫
Scale In

Recarregue a página para ver as animações novamente

Animações de Entrada/Saída animations.css
/* 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 com Animação Completa modal.html
<!-- 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!

Responsividade Próximo: Projeto Final