Framer Motion para transições e elementos React

Framer Motion para transições e elementos React

A cada dia que passa o mundo da programação front end é empurrado para o foco na experiência do usuário. Uma boa interação entre a nossa aplicação e quem a utilizará define o sucesso ou não do que estamos fazendo e, neste aspecto, o processo de estilização é essencial.

Pensando nisso, trazemos neste artigo um tutorial sobre como utilizar uma das funcionalidades de uma biblioteca chamada Framer Motion, focada na criação e na estilização de efeitos. Hoje, aprenderemos a criar transições na navegação de páginas react, proporcionando uma suavização e uma melhor interação. Preparada/o? Então vem comigo!

Framer Motion

O Framer Motion é uma biblioteca de código aberto que proporciona funcionalidades voltadas para a criação de elementos e componentes com eventos complexos, além de também animações, transições e outros efeitos relacionados.

Por meio dele é possível realizar façanhas que demandariam muitas linhas de código e consequentemente certo tempo para o desenvolvimento. Como o tempo vale dinheiro e geralmente não o temos de sobra, nem sempre é possível este tipo de implementação e é neste cenário que o Framer Motion entra.

Figura 1 - Exemplos de animações com o Framer Motion.gif

Primeiros Passos

Como já foi dito, utilizaremos o Framer Motion para criar efeitos entre a alternância de páginas dentro do nossa aplicação React. Para o roteamento entre páginas, será utilizada a biblioteca mais famosa quando se fala do assunto: o React Router Dom na versão 5. Para isto, vamos começar criando um projeto React e, logo depois, instalando tanto o Framer Motion quanto o React Router Dom.

npx create-react-app transition-motion

cd project-react-redux

npm install react-router-dom@v5

npm install framer-motion

npm start

OBS - Foi utilizado o npm como ferramenta de gerenciamento de pacotes, mas sinta-se à vontade para utilizar a que lhe for mais confortável.

No exemplo que iremos desenvolver neste artigo, criaremos uma aplicação que irá receber implementações com o Framer Motion. Serão criados alguns componentes para tal, mas sintam-se à vontade para deixar a criatividade fluir e criar um projeto de acordo com o que acharem melhor. De início, para preparar o terreno para o que será apresentado, faremos algumas coisas:

  • Realizaremos as configurações básicas do React-router-dom, implementando os componentes BrowserRouter, Switch e Route;
  • Criaremos um componente chamado Nav, fixo no topo de cada página onde será possível navegar entre as rotas criadas;
  • Também serão criadas três páginas: uma página chamada Home, outra chamada Content e uma última chamada Contact.
Figura 2 - Configuração básica do React-router-dom (BrowserRoute).
Figura 3 - Configuração básica do React-router-dom e implementação do componente Nav.
Figura 4: Criação do componente Home.
Figura 5: Criação do componente Content.
Figura 6: Criação do componente Contact.
Figura 7: Aplicação em funcionamento.

Como é possível ver, a transição entre uma página e outra é muito ríspida. Queremos suavizar estas transições, torná-las mais agradáveis à vista e, uma vez feita esta estrutura básica, podemos começar a fazer nossas primeiras edições com o Framer Motion.

Configurando o Framer Motion


Antes de mais nada, sempre que precisamos utilizar o Framer Motion, é necessário encapsular o conteúdo de código com dois componentes, importados de ‘framer-motion’:

  • AnimateSharedLayout - Componente nativo da biblioteca que permite a execução de animações de layout na nossa aplicação com o uso da biblioteca;
  • AnimatePresence - Componente nativo da biblioteca que permite que os componentes sejam animados quando são removidos da árvore React (casos em que alternamos entre uma página e outra).

Em termos de hierarquia de componentes, primeiro utilizamos o AnimateSharedLayout e logo depois o AnimatePresence. Geralmente, estes dois componentes envolvem todo o nosso código (e é assim que faremos neste exemplo), mas se for necessário podemos utilizá-los em apenas uma determinada parte do nosso código que terá acesso exclusivo às funcionalidades do Framer Motion.

Figura 8: AnimateSharedLayout e AnimatePresence.

Feito isto, já podemos direcionar a nossa atenção para cada elemento que receberá um evento do Framer Motion. Para cada componente criado que o utilizará, é necessário fazer a seguinte importação:

import { motion } from ‘framer-motion’;

Como nosso foco neste primeiro momento é na página como um todo, iremos trabalhar apenas com o elemento principal. Iremos inserir nele uma pequena transformação, conforme a imagem abaixo:

Figura 9: Transformação com Framer Motion.png.

Ao transformar o elemento <div> em <motion.div>, estamos informando para o Framer Motion que o elemento em questão receberá eventos da biblioteca. É importante destacar que não apenas um único elemento por componente pode possuir implementações da biblioteca, como veremos mais adiante.

Por hora, precisamos configurar quais eventos queremos para nosso elemento criado. Para isto, vamos entender primeiro a funcionalidade de três propriedades que o motion possui:

  • initial - Representa o estado inicial da animação, ou seja, o ponto zero de como o elemento se comportará;
  • animate - É o que vai acontecer quando o componente for inicializado;
  • exit - Trata-se do que acontecerá quando “sairmos” de um componente para outro.

Todas estas três propriedades recebem um objeto como valor, onde colocaremos as especificações da animação. Dentre as chaves desses objetos, é importante destacar a transition. É nela que definimos o tempo de duração da animação (em segundos) e o tempo de atraso para que esta animação seja executada (também em segundos). A chave transition recebe um objeto como valor onde utilizamos, respectivamente, as chaves duration e delay para as funcionalidades citadas.

Antes que nós nos percamos entre objetos e chaves dentro de objetos e chaves, que tal implementar em nossa aplicação algum efeito como exemplo? Com o intuito de suavizar a transição, vamos alterar a opacidade no início, meio e fim do ciclo de vida do componente. A implementação será a mesma para as três páginas Home, Content e Contact:

Figura 10: Configuração inicial das animações com Framer Motion.

Da forma como foi feito, quando a página for acessada (initial), ela começará com uma opacidade de 0.7. Após o tempo 0.5 segundos, ela alcançará uma opacidade de 1 (animate). Esta transição durará 0.5 segundos. Por fim, quando o usuário sair da página, uma transição também será iniciada (exit): a opacidade irá de 1 para 0.7 em 0,5 segundos:

Figura 11: Primeiras impressões pós Framer-Motion.

Transições em múltiplos elementos


É possível combinar os elementos configurados com o motion de forma que eles tenham eventos relacionados uns aos outros. Tomemos como exemplo a página Content, que possui quatro elementos de imagens. Imaginem que nós queremos que, ao invés das quatro imagens surgirem de uma vez, uma imagem só seja carregada após a outra ter sido.

Pensando no que já vimos, basta colocar um delay maior que o da imagem anterior. Sendo assim, se a primeira imagem começa a surgir na tela após 0.6 segundos, a segunda surgiria após 0.6 segundos, a terceira após 0.7 segundos e assim sucessivamente:

Figura 12: Configurando imagens para surgir uma após a outra.

Figura 13: Imagens surgindo uma por vez.

Configurando os elementos com elementos externos

Pensando um pouco no que aprendemos e vimos até aqui, é um pouco cansativo repetirmos para cada elemento estas propriedades do Framer Motion. E se fossem mil imagens? Para resolver essa questão, o Framer Motion também oferece uma funcionalidade para que configuremos as propriedades de um elemento fora dele.

Antes disso, vamos melhorar o nosso código? Como a criação das quatro imagens se mostra um tanto repetitiva, que tal utilizarmos um map que percorre um array com o nome destas imagens e cria um elemento para cada uma destas posições? Desta forma, escreveremos uma única vez o que foi feito quatro vezes anteriormente:

Figura 14: Refatorando as imagens do componente Content.


Agora, vamos transferir tudo o que está dentro das propriedades initial, animate e exit para um objeto, que chamaremos de objectAnimation. As chaves deste objeto podem ter qualquer nome de sua preferência e, para este exemplo, utilizaremos hidden (para o conteúdo de initial), visible (para o conteúdo de animation) e exit. Com as devidas alterações aplicáveis para que a constante seja aceita como um objeto, teremos o seguinte:

Figura 15: Criando objeto com as propriedades necessárias para o Framer Motion.

Agora, precisamos informar para o nosso elemento motion que criamos um objeto que possui as configurações para a animação. Para isto, repassaremos para uma nova propriedade chamada variants a constante objectAnimation, além de, para as propriedades initial, animate e exit, uma string com o nome de cada chave respectiva criada no objeto:

Figura 16: Elemento motion com as devidas implementações do objeto externo.

Bem melhor, não acha? Só que ainda há uma questão: lembra que estas imagens estavam organizadas anteriormente de forma que uma só era inicializada após a outra? Da forma como reorganizamos, todas as imagens vão aparecer ao mesmo tempo, pois o nosso delay está estático.

Para torná-lo dinâmico, uma sugestão seria utilizar o index de cada posição do array de imagens para que, somado ao delay, cada imagem tenha um tempo próprio e maior que o anterior. Para exportar esta informação do index (que só pode ser visualizada dentro do map) utilizamos a propriedade custom:

Figura 17: Compartilhando a variável index por meio da propriedade custom.

Já no objeto, todas as chaves que precisam acessar o valor de index precisam ter o valor de uma função que recebe index como parâmetro e que retorna um objeto, conforme exemplificado abaixo:

Figura 18: Configurando o objeto para tornar o delay dinâmico para cada imagem.

Desta forma, podemos utilizar o index (posição do array da imagem) para que, somado com o delay padrão e multiplicado por 0.1, seja atribuído um valor de delay diferente para cada imagem.

Considerações finais

Nosso objetivo neste artigo foi mostrar como podemos melhorar e embelezar nossa estilização com o uso da biblioteca Framer Motion. Utilizamos uma das funcionalidades que ela contém para mostrar o quanto é fácil de realizar certas ações, se comparado a realizar sem biblioteca alguma.

É importante destacar que esta é uma pequena ideia do que o Framer Motion pode oferecer e que existe uma documentação onde podemos encontrar diversas outras funcionalidades bem legais, assim como estas transições que ele nos proporciona. Assim como nos aventuramos a aprender, você também pode!

⚠️
As opiniões e comentários expressos neste artigo são de propriedade exclusiva de seu autor e não representam necessariamente o ponto de vista da Revelo.

A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.