Transição e animação sem exagero
Transição
.acao {
background: var(--realce);
transition: filter 200ms ease;
}
.acao:hover {
filter: brightness(1.1);
}
A transition vai no estado normal, não no :hover. Assim ela vale nos dois
sentidos: entrando e saindo. Declarada só no :hover, a entrada é suave e a
volta é seca.
transition: propriedade duração curva atraso;
transition: opacity 200ms ease-in-out 0ms;
Várias, separadas por vírgula:
transition:
opacity 200ms ease,
transform 200ms ease;
Não use transition: all
/* Ruim */
transition: all 200ms;
/* Bom */
transition:
border-color 240ms ease,
transform 200ms ease;
all anima tudo: inclusive propriedades que você mudou por outro motivo, e
inclusive as caras de animar. Listar o que se quer é mais previsível e mais
rápido.
O que é barato animar
O navegador desenha um quadro por vez. Algumas propriedades o obrigam a recalcular o layout inteiro a cada quadro; outras ele entrega direto à placa de vídeo.
| Barato | Caro |
|---|---|
transform | width, height |
opacity | margin, padding |
filter | top, left, right, bottom |
/* Caro: recalcula o layout a cada quadro */
.cartao:hover {
margin-top: -4px;
}
/* Barato: a placa de vídeo resolve */
.cartao:hover {
transform: translateY(-4px);
}
O efeito visual é o mesmo. Num aparelho simples, a diferença entre um movimento liso e um movimento aos trancos - e o portfólio vai ser aberto em aparelhos simples.
A curva importa mais que a duração
transition: transform 240ms cubic-bezier(0.32, 0.72, 0, 1);
ease, ease-out e linear são atalhos para curvas prontas. Uma curva escrita
à mão como a de cima - rápida no começo, desacelerando no fim - é o que faz um
movimento parecer "caro" sem durar mais. Vale guardá-la numa variável:
:root {
--curva: cubic-bezier(0.32, 0.72, 0, 1);
--tempo: 240ms;
}
.cartao {
transition: border-color var(--tempo) var(--curva);
}
Animação com keyframes
@keyframes surgir {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.abertura > * {
animation: surgir 500ms var(--curva) both;
}
Com etapas intermediárias:
@keyframes pulsar {
0%,
100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0;
transform: scale(2.2);
}
}
A bolinha do selo de disponibilidade
É o único movimento contínuo que um portfólio precisa - e é pequeno de propósito:
.selo-estado {
position: relative;
display: inline-flex;
width: 8px;
height: 8px;
}
.selo-estado::before {
content: "";
position: absolute;
inset: 0;
border-radius: 999px;
background: var(--realce);
animation: pulsar 2s ease-in-out infinite;
}
.selo-estado::after {
content: "";
position: absolute;
inset: 0;
border-radius: 999px;
background: var(--realce);
}
Duas camadas: uma parada e uma que cresce e some. É o efeito de "sinal ao vivo" que se vê ao lado de "Disponível para projetos".
E repare que a bolinha é ::before/::after - decoração pura, sem nenhum
texto. A palavra "Disponível para projetos" está escrita ao lado, no HTML. Quem
não vê a bolinha não perde nada.
A entrada da abertura, com escalonamento
.abertura > * {
animation: surgir 600ms var(--curva) both;
}
.abertura > *:nth-child(2) {
animation-delay: 80ms;
}
.abertura > *:nth-child(3) {
animation-delay: 160ms;
}
.abertura > *:nth-child(4) {
animation-delay: 240ms;
}
O selo entra, depois o nome, depois a função, depois os botões. É o efeito que faz uma abertura parecer trabalhada, e são doze linhas.
both no fim da declaração é o que impede o elemento de piscar: sem ele, o item
com atraso aparece, some e reaparece.
Quanto tempo
| Duração | Para quê |
|---|---|
| 100–150ms | resposta a um toque |
| 200–300ms | mudança de estado, abrir e fechar |
| 300–600ms | entrada de conteúdo |
| acima disso | quase sempre demais |
Quem não quer movimento
Movimento na tela causa enjoo, tontura e desconforto em muita gente: e o sistema operacional já oferece uma preferência para isso. Respeite-a:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Este é um dos poucos lugares em que !important se justifica: a regra existe
justamente para vencer qualquer animação declarada em qualquer lugar da folha.
O cartão com movimento contido
.cartao {
border: 1px solid var(--borda);
border-radius: var(--raio);
padding: var(--espaco-4);
transition:
transform var(--tempo) var(--curva),
border-color var(--tempo) var(--curva);
}
.cartao:hover {
transform: translateY(-2px);
border-color: var(--borda-forte);
}
Dois pixels. Não oito, não uma sombra colorida, não uma escala. Num portfólio de seis cartões, o efeito discreto repetido seis vezes lê como cuidado; o efeito exagerado repetido seis vezes lê como festa.
No portfólio
O movimento entra, e entra pouco:
--curvae--tempono:root;- transição de
transformeborder-colornos cartões, com 2px de deslocamento; - transição de
filternos botões; - a bolinha pulsando no selo de disponibilidade - uma na página;
- a entrada escalonada da abertura, com no máximo 300ms de atraso acumulado;
- o bloco
prefers-reduced-motionno fim da folha; - nenhum
transition: allem lugar nenhum.
Depois ligue "reduzir movimento" nas configurações do sistema e recarregue. A página inteira deve ficar parada, e continuar perfeitamente utilizável.
Exercícios
- Ponha uma transição no botão e confira que ela funciona na ida e na volta.
Depois mova a declaração para dentro do
:hovere compare. - Anime o cartão com
translateYno hover e compare commargin-top, usando as ferramentas do navegador para medir os quadros. - Escreva o
@keyframesda bolinha e monte o selo de disponibilidade. - Faça a entrada escalonada da abertura e cronometre o tempo total até tudo estar visível.
- Adicione o bloco de
prefers-reduced-motione teste ligando a preferência no sistema. - Procure
transition: allna sua folha e troque por uma lista explícita.
Referências
- Transições - MDN - sintaxe e curvas
- Animações - MDN - keyframes e controle
prefers-reduced-motion- MDN - por que respeitar
Testa o que você leu
6 perguntas sobre esta aula. Errar aqui não custa nada - a explicação vem junto da correção.