Já faz algum tempo que uso o mesmo padrão de animação em meus projetos para animar elementos na tela. Em sua forma mais simples, você teria um elemento estilizado com opacidade zero e, em seguida, alteraria o estilo para ter uma opacidade de um com uma transição CSS de um segundo.
Podemos desenvolver isso adicionando outras propriedades de transição, alterando a duração, adicionando um atraso ou definindo uma atenuação personalizada.
<AnimateIn/> é um componente React reutilizável que criei para usar sempre que quiser adicionar rapidamente alguns efeitos de animação aos meus projetos. Um componente utilitário simples, ele combina animação CSS com classes Tailwind para criar animações fluidas e atraentes com o mínimo de esforço.
Vamos dar uma olhada em como ele é usado. Após importar o componente, defina os estados from
e to
com classes Tailwind. Envolva o elemento de destino em <AnimateIn/> para ver a animação ganhar vida.
import AnimateIn from '../animation/AnimateIn'; <AnimateIn from="opacity-0 scale-90" to="opacity-100 scale-100" duration={500} > <YourComponent /> </AnimateIn>
Aqui está um exemplo um pouco mais complexo que usa mais propriedades para animar um título e um subtítulo.
import AnimateIn from '../animation/AnimateIn'; <header> <AnimateIn as="h1" from="opacity-0 translate-y-32" to="opacity-100 translate-y-0" delay={500} duration={300} className="text-4xl" style={{transitionTimingFunction:"cubic-bezier(0.25, 0.4, 0.55, 1.4)"}} > My Big Headline </AnimateIn> <AnimateIn as="h2" from="opacity-0 scale-0" to="opacity-100 scale-100" delay={800} duration={500} className="text-lg" > This is a subtitle below the headline </AnimateIn> </header>
No exemplo do título, <AnimateIn/> é usado para criar um efeito deslizante combinado com um fade-in. Veja como cada propriedade contribui para a animação:
as
: Ao definir as="h1"
, dizemos ao AnimateIn para renderizar a animação como um elemento <h1>
.
from
e to
: A propriedade from
inicia o título fora da tela ( translate-y-32
, movendo-o 32 unidades para baixo) e invisível ( opacity-0
). A propriedade to
então traz o título para sua posição final (de volta para translate-y-0
) e o torna totalmente visível ( opacity-100
).
duration
: a animação é definida para começar imediatamente, sem atraso, e dura 300 ms.
className
: O className="text-4xl"
aplica a classe de utilitário do Tailwind para definir o tamanho da fonte, fazendo com que o título se destaque.
style
: a transitionTimingFunction
personalizada ( cubic-bezier(0.25, 0.4, 0.55, 1.4)
) adiciona uma facilidade única à animação, dando-lhe um efeito de salto.
A legenda usa um conjunto diferente de animações para complementar o título, criando um fluxo visual coeso.
as
: aqui, as="h2"
renderiza o componente como um elemento <h2>
, adequado para uma legenda.
from
e to
: A legenda começa reduzida a zero ( scale-0
) e invisível ( opacity-0
), depois aumenta até seu tamanho natural ( scale-100
) e se torna totalmente visível ( opacity-100
). Este efeito de escala, combinado com um fade-in, adiciona profundidade à animação.
delay
e duration
: a legenda também começa após um atraso de 800 ms, para que comece depois que o título estiver totalmente animado. Essa abordagem escalonada garante que cada elemento tenha seu momento de foco.
className
: O className="text-lg"
define o tamanho da fonte da legenda, tornando-a menor que o título, mas ainda significativa.
Para entender melhor o que está acontecendo, vamos dar uma olhada no código fonte de <AnimateIn/> no Github :
<AnimateIn/> usa um gancho useState
para inicializar o estado da animação com a propriedade from
, que deve ser uma ou mais classes de utilitário Tailwind, preparando o cenário para o ponto inicial da animação antes que qualquer animação ocorra.
O primeiro gancho useEffect
no componente é para respeitar as preferências do usuário para movimento reduzido. Ao ouvir a consulta de mídia (prefers-reduced-motion: reduce)
, o comportamento da animação é baseado nas configurações do sistema do usuário. Se o movimento reduzido for preferido, a animação será totalmente ignorada, definindo diretamente o estado da animação para a propriedade to
, permitindo uma experiência acessível.
O segundo gancho useEffect
é onde reside a lógica da animação. Se o usuário não indicou uma preferência por movimento reduzido, o componente define um temporizador que altera o estado da animação from
valor inicial to
o valor final após o atraso especificado. Essa transição cria o efeito visual de animação.
A função de limpeza deste gancho (a instrução return) limpa o cronômetro, evitando possíveis vazamentos de memória, como se o componente fosse desmontado antes da conclusão da animação.
A chamada da função React.createElement
é o mecanismo de renderização do componente. Ele cria dinamicamente um elemento HTML baseado na propriedade as
, permitindo o uso do componente em diferentes elementos HTML. O className
é construído usando a função cn
popularizada por shadcn , que combina as classes de utilitário do Tailwind, o className
personalizado passado como um suporte e o estado atual da animação. Essa atribuição dinâmica de classe é o que aplica os estilos e transições desejados ao elemento.
Além disso, há um atributo style
que pode ser passado para definir diretamente as propriedades de estilo no contêiner de animação. A transitionDuration
é definida com base na propriedade duration
, mas muda de forma inteligente para 0ms
se o usuário preferir movimento reduzido, desativando efetivamente a animação enquanto mantém a funcionalidade do componente.
Se você quiser usar <AnimateIn/> em seu próprio projeto e ele já usa shadcn , então você já tem tudo que precisa, basta baixar AnimateIn.tsx e adicioná-lo aos seus componentes.
Caso contrário, você desejará instalar o Tailwind , bem como mxcn
o utilitário útil para mesclar classes do tailwind.
Assim como o shadcn, <AnimateIn/> foi criado para ser um componente reutilizável que você pode copiar e colar em seus aplicativos e personalizar de acordo com suas necessidades. O código é seu.
Além disso, criei uma bela página de demonstração para brincar com a criação de diferentes animações com <AnimateIn/> em animate-in.vercel.app .
Também publicado aqui