d

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.

15 St Margarets, NY 10033
(+381) 11 123 4567
ouroffice@aware.com

 

KMF

Framer Motion Tutorials: Make More Advanced Animations

Framer Motion is a relatively new and popular open-source React animation library, aimed at creating production-ready animation. Framer Motion is Pose’s animation library next-in-line. It possesses a low-level declarative API and can be used irrespective of platform, for the web as well as for mobile apps. Its other advantage valued by the software developers is that it’s also possible to get it as a separate package for use in React apps.

Framer’s documentation provides enough tutorials on how to do the simplest gestures and motion. However, if you are working with more sophisticated cases, there’s too little information on the web in this respect. So it makes no sense to delve into the simplest examples, they can be done according to the documentation. There are also articles on this topic (albeit not very many of them) on the web. Let’s tinker with more complex Framer animations instead.

If you’ve ever wondered how to make this or that butter-smooth effect like, for example, on the Dribbble Global Design Survey 2019 page, then read on and learn from this Framer Motion tutorial!

When to Use Framer Motion and Why

Framer Motion is capable of powering animations in Framer X, a prototyping tool, which makes the hand-off extremely convenient. The majority of designers have suffered a situation when they spend ages perfecting every little detail of design only to have it lost in the development process. Framer Motion lets you use the same animation library both in prototyping and production. This way you don’t need to worry your React animations are different from what you’ve intended them to be.

As for the best way to use animation as an instrument in general, the main thing is to keep it meaningful and relevant to the subject. You can grasp the main idea and a dozen useful tips in this article. And now, let’s move on directly to our React animations tutorial.

Framer Motion Tutorials

Framer Motion is great for animations. Let’s try doing some of those! If at the moment you’re at the beginning of your JavaScript journey, then you’d be better off with simpler things first.

Each Framer Motion tutorial consists of 1-3 components with a list of props (most of which are optional and/or have default values). All examples are interactive, so refresh and click, drag, flip.

Parallax Box Tutorial

ParallaxBox component animation is set in motion by scrolling, imitating the parallax effect. Scroll the triggers component to shift up/down (depending on the scroll direction) by the value specified in theyOffsetprop (px, >0, by default =100).MotionValuesare used to track the state and speed of an animating value. Usually automatically calculatedMotionValuesis more than enough for most cases. But for more advanced ones, you can create them manually, and then inject them into components. We’ll do just that.

To animate theParallaxBoxcomponent, use the chain of MotionValues, that are passed to theParallaxBoxvia the useTransform hook (useTransform (parent, from, to, options)).

const y = useTransform(
  scrollY,
  yRange, 
  [0, -yOffset], 
  easing
)

useTransformcreates aMotionValuethat transforms the output of another MotionValue by mapping it from one range of values into another.

The first parameter, parent: theMotionValueto transform the output of.

We’ll use another hook as it’s value:

const { scrollY } = useViewportScroll();

useViewportScroll(): ScrollMotionValuesprovidesMotionValuesthat update when the viewport scrolls. 
scrollY: vertical scroll distance in pixels. Input values from:number[], a linear series of numbers (all either increasing or decreasing).

const yRange = [transformInitialValue, transformFinalValue];

yRangeaccepts an array consisting oftransformInitialValue, the initial position of the element and transformFinalValue, its position at the end of the animation.

Output values to:T [], a series of numbers, colors, or strings. Must be the same length asinputRange.

In the example, the output values take an array:

[0, -yOffset]

where 0 = initial position, -yOffset= element offset (the value is negative since the component is shifted upward relative to its initial position).

The last value thatuseTransformtakes, options, can take several values, but in this example, the most significant for us is ease:EasingFunction [].

easing = [0.42, 0, 0.58, 1],

Easing functions are algorithms that let you control the animation speed to give them the desired effect like bouncing, deceleration, etc.

That is, in real life things don’t start and stop moving abruptly and in a linear fashion. Momentum and other physical aspects play their part. For example, when you play ball you keep in mind that it doesn’t move at a constant speed but bounces. A car decelerates while turning, etc. Easing functions help make effects look more natural and life-like. Easing can take either an array of four numbers [n, n, n, n] known as a cubic-bezier function or built-in named functions like ‘linear‘, ‘easeInOut‘, etc.

Now all that remains is to pass theyvalue into the component:

return (
   <MotionBox ref={ref} initial={{ y: 0 }} style={{ y, opacity }}>
     {children}
   </MotionBox>
 );

Job’s done! Now the component will smoothly shift up while scrolling, imitating the parallax effect.

You can also pass props into the component:

  • yOffset: offset value.
  • easing: animation type.
  • triggerPoint: a value between 0 and 1, which determines when the animation of this element is to begin, depending on its position on the page, where 0 is the top of the page and 1 is its bottom.
  • fadeOutis a boolean value that determines whether the element’s fading out will affect its opacity level.

All listed props are optional and already have default values specified in the component. Easy, isn’t it?

Intersection Observer | Scale Box Tutorial

This tutorial is much simpler than the previous one. The only difficulty is using a hook from a third-party library react-use, useIntersection, React sensor hook that tracks the changes in the intersection of a target element.

With the help of this hook, we can create theIntersectionObservercomponent that senses when the motion component appears in its scope and starts the animation.

This component can take a boolean prop reset, withdefault = false, which is responsible for whether the animation will be triggered when the element appears in the viewport again.

Now we can wrap one or more motion components with theIntersectionObservercomponent:

<IntersectionObserver>
  <ScaleBox />
</IntersectionObserver>

And pass theinViewvalue to themotioncomponent from the context of theIntersectionObservercomponent:

const { inView } = useContext(IntersectionContext);

Let’s move on to the motion component,ScaleBoxAscalevalue allows you to reduce or increase the size of an element. That is, when the ScaleBoxfalls into the visible part of the browser window,IntersectionObserverchanges the value from theinViewcontext totrue, which will trigger the animation:

animate={inView ? "show" : "hidden"}

ScaleBoxcan be used outside the IntersectionObservercomponent, but then the animation will start after the page loads and will be processed regardless of whether it is in the visible area or not. Often, this is not the way we would like a motion component to act, this is why we need the IntersectionObserver.To describe theScaleBoxanimation we usevariants, sets of pre-defined target objects:

const variants = {
   hidden: {
     scale: 0,
     opacity: 0,
     transition
   },
   show: {
     scale: 1,
     opacity: 1,
     transition
   }
 };

Thevariantsobject contains key-value pairs, where the keys (labels) are names for the animation properties (in our case, it is ‘hidden’ and ‘show’, although the names can be anything. The main thing is to keep them meaningful).

The only thing that remains is to pass thevariantsobject to variants prop:

return (
   <MotionBox
     initial="hidden"
     animate={inView ? "show" : "hidden"}
     exit="hidden"
     variants={variants}
   >
     {children}
   </MotionBox>
 );

Variants can set an animation target that is indicated by its labels (for example,initial=”hidden”).

It is also worth considering in more detail the transition property, with which you can set animation execution parameters like duration(s),  delay(s), ease.

const transition = {
  duration: 0.4,
  delay: 0.2,
  ease: "easeInOut"
 };

There are other parameters that can be passed totransition, for example,loop, the number of iterations of the animation (accepts anumberorInfinity).

As a result, we got two components. The first,Intersection Observer, detects the presence of the motion element on the screen. The second one,ScaleBox, changes the element’s size. Both components are quite simple. Using them together allows animating the content appearing on the page when it is displayed in the user’s viewport.

Fade-in-up Box | Stagger Tutorial

FadeInOutBox: a component that animates the appearance of an element, its shift from bottom to top (yOffset) and its opacity.

LikeScaleBox, this component uses variants:

 const variants = {
   hidden: { 
y: yOffset, 
opacity: 0, 
transition 
   },
   show: {
     y: 0,
     opacity: 1,
     transition   
   }
 };

Only in this case, theyproperty (transforming an element’s position along the y-axis) is animated, not the scale.

The second component of this example isStaggerWrapanimating the nested motion components sequentially with a certain delay (staggerChildren).

const variants = {
   hidden: { opacity: 0 },
   show: {
     opacity: 1,
     transition: {
       when: "beforeChildren",
       staggerChildren: 0.5
     }
   }
 };

When the prop helps to detail the association between parent and its children (false by default). It also can take the ‘beforeChildren‘ value if the parent’s animation has to execute before the children’s one or ‘afterChildren‘ for the opposite case. In this case, the animation parameters are transferred to the parent, that is, to theStaggerWrapcomponent itself:

 return (
   <StaggerContext.Provider value={{ stagger: true }}>
     <MotionBox
       initial="hidden"
       animate="show"
       exit="hidden"
       variants={variants}
     >
       {children}
     </MotionBox>
   </StaggerContext.Provider>
 );
};

The only thing left is to pass thevariantsobject into the props options of the children elements:

return stagger ? (
   <MotionBox variants={variants}>
     {children}
   </MotionBox>
 ) : [...]

UsingStaggerWraptogether withFadeInUpBoxallows you to sequentially animate the appearance of multiple elements with a shift ony(yOffset) and an opacity change. 

AnimatePresence | Routing Tutorial

With Framer-motion’s component AnimatePresence and React-Router, we can set up beautiful and seamless transitions between pages to boost up your project’s looks ✨Framer-motion already has a demo with routing, but it’s a bit uneven and might be difficult to understand having no explanations in the docs. So we decided to figure it out with our own little demo and tutorial.

Basically, this demo consists of the main blog page (Blogcomponent) with a blog posts list (PostPreview) and individual post pages (Post). You can navigate to posts by clicking the Learn more link and return back by clicking the Back to Home Page link. Navigating between the pages triggers enter and exit animations of components insideAnimatePresenceFirst of all, we need to set up routing, if you are not familiar with the subject, please check out docs: Basic Routing (react-router-dom).

<Router>
	<Route
	  render={({ location }) => (
	    <AnimatePresence exitBeforeEnter initial={false}>
	      <Switch location={location} key={location.pathname}>
	        <Route exact path="https://dzone.com/" component={Blog} />
	        <Route exact path="/post/:id" component={Post} />
        </Switch>
      </AnimatePresence>
    )}
  />
</Router>

In a nutshell, Router works something like this: depending onlocation, valueSwitchrenders the first childRoutethat matches the current location. If its Home page location is"https://dzone.com/"and if it’s one of the posts it is"/post/:id"("/post/0", "/post/1", etc). To actually render a component inside Router we need to pass it to Routeas a prop:

<Route {...} component={Component} />

Or wrap acomponentwith it like this:

<Route {...} ><Component /></Route>

Also, we need to wrapSwitchwith Framer-motion’sAnimatePresenceto enable animation even if our components are removed from the React tree.

Let’s take a closer look at props that we need to pass toAnimatePresence:

  • exitBeforeEnterensures that components will only render one at a time, so the exiting component will finish its exiting animation before the entering component is rendered;
  • initial={false}is disabling initial animation when the component is first rendered (i.e., when a page is loaded the first time).

The next step is to create our components. We’ll start withBlog:

const blogVariants = {
  enter: { transition: { staggerChildren: 0.1 } },
  exit: { transition: { staggerChildren: 0.1 } }
}

const Blog = () => (
	<motion.div
		initial="initial"
		animate="enter"
		exit="exit"
		variants={blogVariants}
	>
		{content.map((post) => (
			<PostPreview key={post.id} {...post} />
		))}
</motion.div>
);

staggerChildrenhelps us create staggered orchestrated animation (which means that each next item in a list has a 0.1 delay from the previous one), but you can removevariants={blogVariants}if you don’t need it.

Next, let’s look at ourPostPreviewcomponent that we map insideBlog. We wrap up our content withmotion.divand passing variants with our animation values.

Also, we need to addLinkto navigate to our post pages, let’s pass thetoprop that takes the route path, make sure to addid (to={/post/${id}})of our post to ensure that routing works properly.

const transition = { duration: 0.5, ease: "easeInOut" };

const postPreviewVariants = {
  initial: { x: "100%", opacity: 0 },
  enter: { x: 0, opacity: 1, transition },
  exit: { x: "-100%", opacity: 0, transition }
};

const PostPreview = ({ id, {...} }) => (
	<motion.div variants={postPreviewVariants}>
		{...}
    <Link to={`/post/${id}`}>Learn more</Link>
	</motion.div>
);

And last but not least, thePostcomponent:

const transition = { duration: 0.5, ease: "easeInOut" };

const postVariants = {
  initial: { y: 100, opacity: 0 },
  enter: { y: 0, opacity: 1, transition },
  exit: { y: -100, opacity: 0, transition }
};

const Post = ({ match }) => {
  const id = Number(match.params.id);

	const { title, ... } = content[id];

  return (
    <motion.div
      initial="exit"
      animate="enter"
      exit="exit"
      variants={postVariants}
    >
	    <Link to="https://dzone.com/">Back to Home page</Link>
      {...}
    </motion.div>
  );
};

match object contains information about how our route path matches the URL. Withmatch, we can access many useful properties, but the only one that is relevant in our case is post id (match.params.id) which we need to access the content of the current post.

We also define our animation (postVariants) and pass it to variants of motion.div.

The last step is to addLinkto enable navigation back to the Home page.

That’s all! Now each time we navigate between pages the exit animation is triggered, making the process smooth.

Drag Slider

This component uses theuseMotionValuehook to change the value ofx(that is, for the slider flipping) to a drag gesture (drag = ”x”).

Using the IntersectionObserver, FadeInOutBox, and ScaleBoxcomponents we already know, you can pass ‘scale‘ | ‘fadeIn values toslideApperanceprops to add animation to the appearance of slides.

This slider is far from perfect:overflow-x: hiddenon slider wrapper makes it impossible to implement scroll on mouse wheel motion.

Also, it often gets reset on the last slide to its original position for some yet unknown reason.

Motion Slider

Another slider that works not only on drag but also on controls (arrows and bullets).In order to animate the state of the slide on unmount, we need to use theAnimationPresencecomponent and passexitBeforeEnterprop to correctly finish its exit animation before the next component render.

It’s not a perfect example. In particular, bullet animation only works in one direction and uses the third-party library.

Progress Circle and Progress Bar

These are just fooling around with some animations on the Dribbble’s Global Design Survey page and trying to make something similar.

Some components for displaying statistical information. Best work in combination with IntersectionObserver.

Fade In Up Box | Scale Box

Another take on Dribbble. There are already familiarStaggerWrapcomponents in this example,FadeInUpBoxfor animating text, andScaleBoxfor animating images. In general, the animation is quite simple, but it looks impressive and interesting.

To Wrap Up

In general, Framer Motion is a multifunctional, flexible, and modern React animation library. Motion is a flexible tool that is great both for beautifully smooth and simple React animations and for more advanced sequences. All with as little amount of code as possible. Its main issue is that a significant part of its functionality is either poorly and fragmentarily described in the documentation, or not described at all. Because of that, you might spend time learning things instead of implementing them.

Happy if this Framer Motion tutorial helps you to figure out how to build your own motion components with stunning animations, and make your job at least a bit easier. Written by Julia Shikanova and Kate Shokurova.

* * *

This Framer Motion tutorial was originally published in January 2020 and was updated in December 2020 to make it more relevant and comprehensive.

Credit: Source link

Previous Next
Close
Test Caption
Test Description goes like this