Framer Motion para transiciones y elementos de React
Cada día, el mundo de la programación frontend se ve empujado hacia un enfoque en la experiencia del usuario (UX). Una buena interacción entre nuestra aplicación y quien la usará define el éxito o no de lo que estamos haciendo y, en este aspecto, el proceso de estilización es fundamental.
Con eso en mente, en este artículo presentamos un tutorial sobre cómo usar una de las características de una biblioteca llamada Framer Motion, enfocada en crear y diseñar efectos. Hoy, aprenderemos cómo crear transiciones en la navegación de las páginas de reacción, brindando fluidez y una mejor interacción. ¿Lista/o?
¡Entonces ven conmigo!
Framer Motion
Framer Motion es un marco de trabajo de código abierto que proporciona funciones destinadas a crear elementos y componentes con eventos complejos, así como animaciones, transiciones y otros efectos relacionados. A través de él es posible realizar hazañas que requerirían muchas líneas de código y, en consecuencia, algo de tiempo para desarrollo.
Como el tiempo vale dinero y no solemos tenerlo en exceso, este tipo de implementación no siempre es posible y este es el escenario donde entra Framer Motion.
Primeros pasos
Como ya se mencionó, usaremos Framer Motion para crear efectos entre el cambio de página dentro de nuestra aplicación React. Para el enrutamiento entre páginas se utilizará la librería más famosa en la materia: la React Router Dom en su versión 5. Para ello, comenzaremos creando un proyecto React y, poco después, instalaremos tanto Framer Motion como 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
Nota: Utilizamos NPM como una herramienta de administración de paquetes, pero siéntete libre de usar la que te resulte más cómoda.
En el ejemplo que desarrollaremos en este artículo, crearemos una aplicación que recibirá implementaciones con Framer Motion. Se crearán algunos componentes para esto, pero deja fluir tu creatividad y crea un proyecto de acuerdo con lo que creas mejor. Al principio, para preparar el terreno para lo que se presentará, atenderemos algunos detalles:
- Realizaremos las configuraciones básicas de React-router-dom, implementando los componentes BrowserRouter, Switch e Route;
- Crearemos un componente llamado Nav, fijo en la parte superior de cada página donde será posible navegar entre las rutas creadas;
- También se crearán tres páginas: una página llamada “Inicio”, otra llamada “Contenido” y una última llamada “Contacto”.
Como puedes ver, la transición entre una página y otra es muy tosca. Queremos suavizar estas transiciones, hacerlas más agradables a la vista y, una vez que esta estructura básica esté en su lugar, podemos comenzar a realizar nuestras primeras ediciones con Framer Motion.
Configurar Framer Motion
En primer lugar, siempre que necesitemos usar Framer Motion, debemos envolver el contenido del código con dos componentes importados de 'framer-motion':
- AnimateSharedLayout - Componente nativo de la biblioteca que permite la ejecución de animaciones de diseño en nuestra aplicación utilizando el framework;
- AnimatePresence - Componente de biblioteca nativo que permite animar los componentes cuando se eliminan del árbol React (casos en los que cambiamos de una página a otra).
En términos de jerarquía de componentes, primero usamos AnimateSharedLayout y luego AnimatePresence. Generalmente, estos dos componentes involucran todo nuestro código (y así lo haremos en este ejemplo), pero si es necesario podemos usarlos solo en una cierta parte de nuestro código que tendrá acceso exclusivo a las funcionalidades de Framer Motion.
Una vez hecho esto, podemos dirigir nuestra atención a cada elemento que recibirá un evento Framer Motion. Para cada componente creado que lo utilizará, debe importar lo siguiente:
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:
Al transformar el elemento <div> en <motion.div>, informamos a Framer Motion que el elemento en cuestión recibirá eventos del framework. Es importante señalar que no solo un solo elemento por componente puede tener implementaciones de biblioteca, como veremos más adelante.
Por ahora, necesitamos configurar cuáles eventos queremos para nuestro elemento creado. Para esto, primero entendamos la funcionalidad de tres propiedades que tiene el movimiento:
- initial - Representa el estado inicial de la animación, es decir, el punto cero de cómo se comportará el elemento;
- animate - Esto es lo que sucederá cuando se inicialice el componente;
- exit - Se trata de lo que sucederá cuando nos “movamos” de un componente a otro.
Todas estas tres propiedades reciben un objeto como valor, donde colocaremos las especificaciones de la animación. Entre las claves de estos objetos, es importante destacar la transition. Aquí es donde definimos la duración de la animación (en segundos) y el tiempo de retraso para que se ejecute esta animación (también en segundos). La tecla de transición recibe como valor un objeto donde usamos, respectivamente, las teclas de duration y delay para las funcionalidades antes mencionadas.
Antes de perdernos entre objetos y claves dentro de objetos y claves, ¿qué tal implementar algún efecto en nuestra aplicación como ejemplo? Para suavizar la transición, cambiemos la opacidad al principio, a la mitad y al final del ciclo de vida del componente. La implementación será la misma para las tres páginas de Home, Content y Contact:
De la forma en que se hizo, cuando se acceda a la página (inicial), comenzará con una opacidad de 0.7. Después de 0.5 segundos, alcanzará una opacidad de 1 (animado). Esta transición durará 0.5 segundos. Finalmente, cuando el usuario salga de la página, también se iniciará una transición (exit): la opacidad pasará de 1 a 0.7 en 0.5 segundos:
Transiciones en múltiples elementos
Es posible combinar elementos configurados con movimiento para que tengan eventos relacionados entre sí. Toma la página Content como ejemplo, que tiene cuatro elementos de imagen. Imagina que queremos que, en lugar de que aparezcan cuatro imágenes a la vez, solo se cargue una imagen después de que se haya cargado la otra.
Pensando en lo ya visto, basta con poner un delay mayor que el de la imagen anterior. Así, si la primera imagen comienza a aparecer en la pantalla después de 0.6 segundos, la segunda aparecerá después de 0.6 segundos, la tercera después de 0.7 segundos y así sucesivamente:
Configurando os elementos com elementos externos
Pensando un poco en lo que hemos aprendido y visto hasta ahora, quizás sea un poco agotador repetir estas propiedades de Framer Motion para cada elemento. ¿Y si hubiera mil imágenes? Para resolver este problema, Framer Motion también ofrece una funcionalidad para que configuremos las propiedades de un elemento fuera de él.
Antes de eso, mejoremos nuestro código, ¿no? Como la creación de las cuatro imágenes es algo repetitiva, ¿qué tal si usamos un mapa que recorre una matriz con los nombres de estas imágenes y crea un elemento para cada una de estas posiciones? De esta forma, escribiremos una sola vez lo que se hizo cuatro veces anteriormente:
Ahora, transfiramos todo lo que está dentro de las propiedades initial, animate y exit a un objeto, al que llamaremos objectAnimation. Las claves de este objeto pueden tener cualquier nombre que desee y, para este ejemplo, usaremos hidden (para el contenido inicial), visible (para el contenido de la animación) y exit. Con los cambios pertinentes aplicables para que la constante sea aceptada como objeto, tendremos lo siguiente:
Ahora, debemos decirle a nuestro elemento de movimiento que hemos creado un objeto que tiene la configuración para la animación. Para hacer esto, pasaremos a una nueva propiedad llamada variants la constante objectAnimation, al tiempo que para las propiedades initial, animate y exit, un string con el nombre de cada clave respectiva creada en el objeto:
Mucho mejor, ¿no crees? Pero aún queda una duda: ¿recuerdas que estas imágenes se organizaban previamente de forma que solo se inicializaba una tras otra? De la manera en cómo lo reorganizamos, todas las imágenes aparecerán al mismo tiempo, ya que nuestro delay es estático.
Para hacerlo dinámico, una sugerencia sería usar el index de cada posición en la matriz de imágenes para que, además del delay, cada imagen tenga su propio tiempo y mayor que el anterior. Para exportar esta información de index (que solo se puede ver dentro del mapa) usamos la propiedad custom:
En el objeto, todas las claves que necesitan acceder al valor del index deben tener el valor de una función que lo toma como parámetro y devuelve un objeto, como se ejemplifica a continuación:
De esta forma, podemos utilizar index (posición de la matriz de imágenes) para que, sumado al delay predeterminado y multiplicado por 0.1, se asigne un valor de delay diferente a cada imagen.
Consideraciones finales
Mi objetivo en este artículo fue enseñar cómo mejorar y embellecer nuestro estilo utilizando la biblioteca Framer Motion. Usamos una de las funciones que contiene para mostrar cuán fácil es realizar ciertas acciones, en comparación con hacerlo sin ninguna biblioteca.
Es importante tener en cuenta que esta es una pequeña muestra de lo que Framer Motion puede ofrecer y que hay documentación donde podemos encontrar otras funciones realmente geniales, así como estas transiciones que proporciona.
¡Nunca dejes de aprender! ¡Hasta luego!
Revelo Content Network da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.