Pular para o conteúdo
murad.guide

A Web Aberta

Capítulo 34

Animações CSS

5 min de leitura 935 palavras 2 gravuras

Esta é o capítulo 34 de 52 do volume Aprenda a Web. O projeto-fio é a Oficina Costeira, um coletivo fictício de design em João Pessoa. O exemplo está em exemplos/34-animacoes-css/. Em cada capítulo: leia, copie, mude uma coisa, preveja, recarregue e confira.

O que você vai aprender

Transição ou animação

Transição tem começo e fim. A pessoa passa o mouse ou o foco, a cor muda em 200 ms. Animação tem vários estágios e pode começar sozinha, em loop.

Se só há dois estados, use transition. Se o selo gira ao carregar ou o cartaz pulsa sozinho, use @keyframes.

a {
  color: #0b4f6c;
  transition: color 0.2s ease;
}

a:hover,
a:focus-visible {
  color: #c45c26;
}

A transição fica no estado inicial. Se você colocar só no :hover, o retorno pisca.

Copie. Mude 0.2s para 2s. Preveja a lentidão. Recarregue. Volte para 0.2s: movimento curto informa, não atrapalha.

Erro comum: transition: all. Propriedades que não devem animar entram na dança. Liste color ou transform.

Transformação

transform move, gira e escala sem quebrar o fluxo tanto quanto top e margin. Funções comuns: translate, rotate, scale. Várias no mesmo valor, separadas por espaço.

.cartao {
  transform-origin: center center;
  transition: transform 0.2s ease;
}

.cartao:hover,
.cartao:focus-within {
  transform: translateY(-0.25rem);
}

:focus-within cobre o cartão com um link dentro, para o teclado ter o mesmo efeito do hover. Não anime só :hover.

transform-origin muda o pivô, como background-position: left top, center bottom.

Neste volume não empilhamos prefixos -webkit- em transform. Os navegadores atuais do material já entendem a propriedade sem prefixo.

Keyframes

Dois pedaços: o nome em @keyframes e a propriedade animation no seletor.

<!DOCTYPE html>
<html lang="pt-BR">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Movimento — Oficina Costeira</title>
    <link rel="stylesheet" href="assets/stylesheets/main.css">
  </head>
  <body>
    <p class="selo">Inscrições fictícias</p>
  </body>
</html>
@keyframes pulso {
  from { transform: scale(1); }
  to { transform: scale(1.05); }
}

.selo {
  display: inline-block;
  animation: pulso 1.2s ease-in-out infinite alternate;
}

from e to são 0% e 100%. Estágios no meio usam porcentagem. infinite repete. alternate vai e volta. Sem alternate, o selo salta do fim para o começo.

Mude infinite para 2. Preveja duas idas. Recarregue.

Resumo dos conceitos: transition, transform, @keyframes

Prefers-reduced-motion

Algumas pessoas enjoam com movimento. O sistema operacional oferece reduzir animações. O CSS pergunta isso.

@media (prefers-reduced-motion: no-preference) {
  a {
    transition: color 0.2s ease;
  }

  .selo {
    animation: pulso 1.2s ease-in-out infinite alternate;
  }
}

Fora da media query, o selo fica parado e o link ainda muda de cor no instante. Quem pediu menos movimento não espera o pulso.

A forma inversa também vale: anime por padrão e zere dentro de prefers-reduced-motion: reduce. O importante é o movimento não ser obrigatório.

No Windows, a opção aparece nas configurações de acessibilidade de animação. Ative, recarregue, confira o selo parado.

Erro comum: esconder texto com animação que nunca termina. Se a pessoa reduz movimento, o texto precisa já estar visível.

O que não animar

Não anime width e height se transform: scale resolve. Não faça a página inteira deslizar ao rolar. Não dispare som. Não use movimento para informação única: cor e texto também devem dizer o mesmo.

Parallax e carrossel automático saem deste volume. Um cartão que sobe 4 px no foco já ensina transição.

:target pode receber uma transição de fundo, sem deslocar o bloco para fora da tela.

.aviso {
  transition: background-color 0.2s ease;
}

.aviso:target {
  background-color: #fff3e8;
}

Conferir hover, foco e preferência

Abra o exemplo. Passe o mouse no link: a cor desliza. Tab: o anel de 3 px aparece e a cor também, se você agrupou :focus-visible. Ative reduzir movimento e recarregue: o pulso some, o anel permanece.

Estreite a janela. Nada deve tremer na carga. Se @keyframes no body empurra o layout, tire. Animação decorativa não empurra conteúdo.

animation-play-state: paused no :hover é um truque. Quem pede menos movimento precisa do corte na media query, não só do hover. O exemplo 34-animacoes-css envolve a transição do link em prefers-reduced-motion: no-preference. Copie esse recorte para o pulso do selo.

Duração: 150 ms a 300 ms para cor e foco. Loop infinito só em enfeite que não esconde texto. animation-delay pode esperar; não use delay longo no conteúdo principal, a pessoa acha que a página travou.

Mude só ease para linear na transição do link. Preveja o ritmo. Recarregue.

Resumo dos conceitos: @keyframes, transform, transition

O que o teclado precisa ver

Movimento no hover sem equivalente no foco exclui quem não usa mouse. Agrupe :hover e :focus-visible quando a mudança for informativa. Se o cartão só “embeleza”, a media query de redução já corta o excesso.

Não anime opacity até 0 num botão que continua clicável. A pessoa não vê o alvo e o Tab ainda para nele. Some de verdade com display só se o conteúdo não for necessário — e mesmo assim o HTML de destino deve existir em outro lugar.

@media (prefers-reduced-motion: reduce) {
  .selo {
    animation: none;
  }

  a {
    transition: none;
  }
}

Este bloco é o inverso do exemplo: corta na preferência reduce. Os dois estilos funcionam. Escolha um e mantenha o arquivo coerente.

Copie o bloco reduce. Ative a opção do sistema. Preveja o selo parado. Recarregue.

Atividades

  1. Onde se declara a transition: no estado inicial ou só no :hover?
  2. Qual media query desliga movimento para quem pediu menos animação?
  3. Por que :focus-within no cartão importa?
  4. animation: ... infinite sem alternativa de redução causa qual problema?
  5. Cite uma propriedade melhor que top para um recuo curto no hover.

Respostas comentadas

  1. No estado inicial. Assim a ida e a volta animam. Só no :hover o retorno pisca.
  2. @media (prefers-reduced-motion: reduce) para zerar, ou colocar as animações dentro de no-preference.
  3. O teclado foca o link interno. Sem :focus-within, só o mouse levanta o cartão.
  4. O movimento não para. Quem enjoa ou pede redução continua vendo o loop.
  5. transform: translateY(...), com transição em transform.

Referências

O arquivo completo

Referência do exemplo 34-animacoes-css, reproduzida aqui para que você possa conferir sem sair da página.

assets/javascript/simulacao.js

const form=document.querySelector("#simulacao");if(form){form.querySelector("button[type=submit]").disabled=false;form.addEventListener("submit",event=>{event.preventDefault();document.querySelector("#retorno").textContent="Simulação concluída. Nada foi enviado ou guardado.";});}