name: motion-and-hover-polish description: Dê à sua interface um ritmo único e um vocabulário de micro-interações de hover e estado: camadas de duração (tap/pop/hover/card/layout) para CSS e Motion, transições de substituição, linhas cujo destaque cresce, setas de acompanhamento, pequenos deslocamentos de chevron, elevação de cartões sem translate, desvanecimento nas bordas de rolagem e trocas de ícone/rótulo para botões de cópia e alternância. Use quando as animações parecerem inconsistentes, as durações forem números mágicos espalhados, os hovers mudarem apenas a cor ou o produto parecer sem vida ou inacabado. licença: MIT
Camadas de movimento e receitas para hover
Duas ideias, comprovadas em 17 protótipos de aplicações:
- Durações são uma escala, não um número por componente. O olho interpreta um ritmo compartilhado como um único produto. Elementos menores se movem mais rápido.
- Hovers movem geometria, suavemente. Um destaque que cresce dentro da linha, uma seta que chega, um chevron que inclina na direção para onde vai, um rótulo que rola para o próximo estado. Hovers que mudam apenas a cor são lidos como uma chave sendo ligada/desligada.
Arquivos
references/recipes.css: Tokens@themee receitas@utilitydo Tailwind v4.references/timing.ts: as mesmas camadas para Motion e WAAPI.references/swap.tsx:IconSwapeLabelSwap(React).
Camadas
| Camada | ms | Para |
|---|---|---|
tap | 100 | alternância de ícone, pressionamento |
pop | 150 | abertura de menu, popover ou dica |
hover | 200 | linha ou controle respondendo ao ponteiro |
card | 300 | elevação de cartão, estabilização de lista, troca de página |
layout | 500 | colapso de painel, refluxo de página |
- Entradas suavizam a saída (
cubic-bezier(0.22,1,0.36,1)). Saídas suavizam a entrada e executam uma camada mais curta. - Quando dois elementos trocam de lugar, o que sai sai imediatamente e o que entra começa com
delay-handoff(50ms) de atraso. - Tweens de valores (um contador, preenchimento de barra, desenho de linha de gráfico) podem executar por mais tempo: o olho está seguindo os dados.
- Mantenha molas intencionais.
Migração: mapeie cada duração ad-hoc para a camada mais próxima.
| Valor ad-hoc | Camada |
|---|---|
| 0.12 | tap |
| 0.15–0.18 | pop |
| 0.2–0.24 | hover |
| 0.28–0.35 | card |
| 0.4–0.5 | layout |
Espere que a temporização na tela mude em menos de 20ms em quase todos os lugares.
Receitas (uma por elemento)
hover-grow(linhas de navegação, linhas de link):- O destaque é um
::beforeque começa interno (3px por 6px) e transparente, depois se expande para a linha inteira enquanto aparece. - Também aparece para
:focus-visible,data-state=openearia-current=page. - Designs quadrados ou brutalistas (estilo Carbon) devem manter um destaque plano.
- O destaque é um
trail(linhas de link, "Navegar planos"):- Um glifo de acompanhamento com metade da escala e transparente até que o
.grouppai seja hover ou foco, crescendo a partir da borda inicial. trail-out(cresce a partir do canto inferior esquerdo) maisarrow-up-rightmarca links que saem da aplicação.
- Um glifo de acompanhamento com metade da escala e transparente até que o
nudge/nudge-back(chevrons, "Ver tudo", links de volta): um deslocamento de 2px na direção do destino.lift(cartões clicáveis):- Uma camada de superfície mais clara e uma camada de sombra mais profunda, durante a camada
card. - Nunca use translate: um cartão que pula sob o cursor move o elemento que está sendo mirado.
- Uma camada de superfície mais clara e uma camada de sombra mais profunda, durante a camada
scroll-fade(painéis com rolagem):- Desvanecimento nas bordas baseado em máscara, apenas no lado que ainda pode rolar. É conduzido pela própria linha do tempo de rolagem do contêiner e não precisa de cor de fundo.
- Navegadores não suportados simplesmente não mostram o desvanecimento.
IconSwap(menu para fechar, copiar para verificado, sol para lua):- O glifo de saída encolhe, inclina −22° e desaparece com ease-in.
- O glifo de entrada segue após o atraso de mão.
- Ambos permanecem montados, então a transição pode ser revertida facilmente.
LabelSwap("Copiar link" para "Copiado", "Recolher" para "Expandir"):- Ambos os rótulos ficam em uma única célula de grade, então não há salto de largura.
- O rótulo oculto fica
invisibleviatransition-discrete, para que a tecnologia assistiva ouça apenas o atual.
Armadilhas
scroll-fadeem um elemento que anima a si mesmo (menu Radix, popover ou conteúdo de select) substitui a animação de saída desse elemento. Radix espera por uma saída que nunca termina, e o menu permanece aberto. Coloque o desvanecimento em um filho com rolagem interna.scroll-fademascara bordas e sombras também. Não coloque em um cartão com borda; coloque no scroller interno.- Utilitários personalizados
duration-*no Tailwind v4 também devem definir--tw-duration, ou uma utilidadetransition-[…]no mesmo elemento vence dependendo da ordem de classificação. - Passos de tipo nomeados que carregam line-height (
--text-meta--line-height) deslocam cada linha convertida em um pixel ao substituir tamanhos arbitrários que herdavam o leading do pai. Dê a passos intermediários nenhum line-height próprio. - Proteja hovers com
@media (hover: hover). Mostre o mesmo estado em:focus-visible, e respeiteprefers-reduced-motion(Motion:<MotionConfig reducedMotion="user">).