惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Webroot Blog
Webroot Blog
AI
AI
P
Palo Alto Networks Blog
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
Spread Privacy
Spread Privacy
T
Tor Project blog
罗磊的独立博客
小众软件
小众软件
S
Security Affairs
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
NISL@THU
NISL@THU
博客园_首页
PCI Perspectives
PCI Perspectives
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Forbes - Security
Forbes - Security
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Security Latest
Security Latest
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Cloudflare Blog
A
About on SuperTechFans
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
宝玉的分享
宝玉的分享
G
GRAHAM CLULEY
雷峰网
雷峰网
F
Full Disclosure
I
Intezer
Cloudbric
Cloudbric
博客园 - 三生石上(FineUI控件)
U
Unit 42

Maxime Heckel's Blog

On Rendering the Sky, Sunsets, and Planets - The Blog of Maxime Heckel Shades of Halftone - The Blog of Maxime Heckel Field Guide to TSL and WebGPU - The Blog of Maxime Heckel On Shaping Light: Real-Time Volumetric Lighting with Post-Processing and Raymarching for the Web - The Blog of Maxime Heckel Speaking at Figma Config 2025 - The Blog of Maxime Heckel Post-Processing Shaders as a Creative Medium - The Blog of Maxime Heckel On Crafting Painterly Shaders - The Blog of Maxime Heckel The Art of Dithering and Retro Shading for the Web - The Blog of Maxime Heckel Moebius-style post-processing and other stylized shaders - The Blog of Maxime Heckel Shining a light on Caustics with Shaders and React Three Fiber - The Blog of Maxime Heckel Real-time dreamy Cloudscapes with Volumetric Raymarching - The Blog of Maxime Heckel Painting with Math: A Gentle Study of Raymarching - The Blog of Maxime Heckel Building a magical AI-powered semantic search from scratch - The Blog of Maxime Heckel Beautiful and mind-bending effects with WebGL Render Targets - The Blog of Maxime Heckel Refraction, dispersion, and other shader light effects - The Blog of Maxime Heckel The magical world of Particles with React Three Fiber and Shaders - The Blog of Maxime Heckel The Study of Shaders with React Three Fiber - The Blog of Maxime Heckel Building a Design System from scratch - The Blog of Maxime Heckel Everything about Framer Motion layout animations - The Blog of Maxime Heckel Building a Vaporwave scene with Three.js - The Blog of Maxime Heckel Cubic Bézier: from math to motion - The Blog of Maxime Heckel First steps with GPT-3 for frontend developers - The Blog of Maxime Heckel Building the perfect GitHub CI workflow for your frontend team - The Blog of Maxime Heckel Migrating to Next.js - The Blog of Maxime Heckel Static Tweets with MDX and Next.js - The Blog of Maxime Heckel Advanced animation patterns with Framer Motion - The Blog of Maxime Heckel Scrollspy demystified - The Blog of Maxime Heckel The Power of Composition with CSS Variables - The Blog of Maxime Heckel My first failed SwiftUI project - The Blog of Maxime Heckel Using Shortcuts and serverless to build a personal Apple Health API - The Blog of Maxime Heckel SEO mistakes I've made and how I fixed them - The Blog of Maxime Heckel Going native: SwiftUI from the perspective of a React developer - The Blog of Maxime Heckel Build your own preview deployment service - The Blog of Maxime Heckel The little guide to CI/CD for frontend developers - The Blog of Maxime Heckel Immigrating to the US - The Blog of Maxime Heckel The physics behind spring animations - The Blog of Maxime Heckel Generate screenshots of your code with a serverless function - The Blog of Maxime Heckel How to use Framer Motion with Emotion styled-components - The Blog of Maxime Heckel Data Fetching with NextJS: What I learned - The Blog of Maxime Heckel Learning in public - The Blog of Maxime Heckel Fixing the dark mode flash issue on server rendered websites - The Blog of Maxime Heckel How to fix NPM link duplicate dependencies issues - The Blog of Maxime Heckel Running scheduled cross-browser end-to-end tests on Github CI - The Blog of Maxime Heckel How I built my first custom ESLint rule - The Blog of Maxime Heckel React Lazy: a take on preloading views - The Blog of Maxime Heckel Automated UI accessibility testing with Cypress - The Blog of Maxime Heckel Building a GraphQL wrapper for the Docker API - The Blog of Maxime Heckel Switching off the lights - Adding dark mode to your React app - The Blog of Maxime Heckel Getting started with Typescript on Gatsby - The Blog of Maxime Heckel Rebuilding Redux with Hooks and Context - The Blog of Maxime Heckel Asynchronous rendering with React - The Blog of Maxime Heckel Using Flow generics to type generic React components - The Blog of Maxime Heckel How to efficiently type your styled-components with Flow - The Blog of Maxime Heckel How I got started with Kubernetes on GKE - The Blog of Maxime Heckel React sub-components Part 3: Whitelisting sub-components with flow - The Blog of Maxime Heckel React sub-components Part 2: Using the new Context API - The Blog of Maxime Heckel React sub-components - The Blog of Maxime Heckel Running Golang tests with Jest - The Blog of Maxime Heckel No title No title
Guide to creating animations that spark joy with Framer Motion - The Blog of Maxime Heckel
Maxime Heckel · 2020-12-15 · via Maxime Heckel's Blog

Over the past few months, Framer Motion went from being a fun tool I played with on the side to a core element of my frontend projects when it comes to adding a layer of interaction to my UIs. I went from knowing almost nothing about animations and transitions, to being able to orchestrate more complex animations involving lots of elements.

I've shared a lot of the animation work I sprinkled throughout my blog on Twitter, and a lot of you have asked me to share more code snippets. Thus I felt it was time for a little write-up!

In this post, you'll find a condensed guide containing everything I've learned when it comes to Framer Motion, the key concepts of animation, and how to use this library to create animations that spark joy through some interactive examples and widgets.

Anatomy of an animation

First, let's take a look at the main elements that define an animation. When working on one, whether it's to move an element, changing its shape, or color, I always try to answer the following 3 questions:

  1. "Where/how is my element at the beginning?" i.e the initial state

  2. "Where it needs to go or which shape it needs to take by the end?" i.e. the target state

  3. "How it's going to transition from the initial state to the end state?" i.e. the transition state

In the case of Framer motion, the library gives us a motion component which takes 3 properties (props) that let us define an answer to the 3 questions above:

  • initial: the state of our element at mount time.

  • animate: the state in which our element will be at the end of the animation.

  • transition: how our element goes from the initial state to the target state. This is where we can define which transition type we want to define, delays, or repetitions of the same transition.

There are many types of transitions available in Framer Motion so I added this little comparative visualization below for you to see the little nuances between some of the main types and tweak their respective options:

You can find the complete list of types and all their respective options in this section of the documentation.

Now that we went through the basics, let's take a look at our first examples! Below you will find a series of animated components that you can edit and tweak at will. As for what to tweak, the following list contains a few interesting points that you can check out:

  • **remove the **transition prop from the first component (Example1). Notice that this translation animation went from an ease type to a spring type. This comes from the "smart defaults" we just mentioned.

  • combine animations in Example2: change the second animation from a simple rotation to a rotation and a translation.

I added hints in the comments of the code to guide you. 😄

Using variants

Now that we've seen and tweaked our first Framer Motion based components, you might notice that, in the case of complex animations, things can quickly get messy. Defining everything inline can lead to your motion components being fairly hard to read but also a bit repetitive.

This is why one of my favorite features of Framer Motion is the ability to define animations in a declarative way through variants.

Variants are sets that have predefined animation objects, the kind of object we passed in the examples above in the animation prop.

The following is an example showcasing how you can leverage variants. Notice how we declared a set of variants within the buttonVariants object and how the respective keys of these variants are referenced in the motion component:

Using variants with the motion component

1

import { motion } from 'framer-motion';

3

const AnimatedButton = () => {

4

const buttonVariants = {

21

variants={buttonVariants}

After seeing these variants the first time, like me, you might be wondering "wait, if everything is predefined, how can I make my animations based on some dynamic property?"

Well, don't you worry! Framer Motion lets you also define variants as functions. Each variant as a function can take one argument and return and animation object. That argument has to be passed in the custom prop of your motion component. The example below showcases an example of variant as function, the hover variant will return a different object whether the button is clicked or not. The state of the button isClicked is passed in the custom prop of the motion component.

Using variants and the custom prop with the motion component

1

import { motion } from 'framer-motion';

3

const AnimatedButton = () => {

4

const buttonVariants = {

8

scale: clicked ? 1 : 1.5,

18

const [clicked, setClicked] = React.useState(false);

25

variants={buttonVariants}

27

onClick={() => setClicked(true)}

Now that we know what variants are, let's try to work with them in the following playground. Let's try to:

  • make the first button scale on hover (for now, it only rotates).

  • make the button not scale back to its original size if it's been clicked on. Hint: you can use the custom prop we just mentioned above 💡.

Like in the first part, I left comments in the code to guide you!

Advanced animations using Motion Values

At this point, we know how to use the key features of Framer Motion to start building our own animations:

  • we know the main elements that define an animation ✅

  • we know how to use variants to define animations in a declarative way ✅

With those newly acquired skills, we can now look at on more concept that will allow us to build more advanced animations: Motion Values. In this part we will learn what are Motion Values and how to use them and also looked at a practical example to illustrate this concept: my own "Copy To Clipboard" button!

Motion Values

A MotionValue is an internal value to the Framer Motion library that "tracks the state and the velocity of an animating value". For more complex animation we may want to create our own MotionValue (quote from the docs), and then add them as inline style to a given component. To define a MotionValue, we need to use the useMotionValue hook.

A MotionValue can be practical when you want to have one animation depending on another one. For example, we may want to tie together the scale and the opacity of a component in such a way that, once the component reaches half of its targeted scale, the opacity should be equal to 100%.

To handle that kind of use case, Framer Motion gives us a second hook: useTransform that transforms an input MotionValue to another MotionValue through a function. The example below showcases how you can use these 2 hooks together:

Dissecting the "Copy To Clipboard" animation

You might have noticed that I sprinkled some animated SVG icons for my buttons throughout my blog ✨. One of my favorite is the "Copy To Clipboard" button on my code snippets, so I figured it would a great case study to look at together to illustrate some of the use cases for Motion Values. It uses both useMotionValue and useTransform to ensure that the opacity level of our checkmark icon is a function of its pathLength.

I added a "dissected" version of this component below to let you fully understand what is happening when clicking on the icon and how the Motion Values change throughout the transition. You can tweak the duration with the slider, and also visualize the MotionValue for the opacity and pathLength of the checkmark SVG.

When clicking on the button, you can see that the more the pathLength increases, the more the opacity of the checkmark increases as well following this function:

3

// Where x is the pathLength of our SVG y is the opacity

which is equivalent to the following code using Framer Motion's hooks:

1

const pathLength = useMotionValue(0);

2

const opacity = useTransform(pathLength, [0, 0.5], [0, 1]);

Here's the code for the full implementation of this component:

Full implementation of the Copy To Clipboard button animation

1

import React from 'react';

2

import { motion, useMotionValue, useTransform } from 'framer-motion';

4

const CopyToClipboardButton = () => {

7

const clipboardIconVariants = {

8

clicked: { opacity: 0 },

9

unclicked: { opacity: 1 },

12

const checkmarkIconVariants = {

13

clicked: { pathLength: 1 },

14

unclicked: { pathLength: 0 },

17

const [isClicked, setIsClicked] = React.useState(false);

19

const pathLength = useMotionValue(0);

20

const opacity = useTransform(pathLength, [0, 0.5], [0, 1]);

25

background: 'transparent',

27

cursor: isClicked ? 'default' : 'pointer',

31

aria-label="Copy to clipboard"

32

title="Copy to clipboard"

43

xmlns="http://www.w3.org/2000/svg"

46

d="M20.8511 9.46338H11.8511C10.7465 9.46338 9.85107 10.3588 9.85107 11.4634V20.4634C9.85107 21.5679 10.7465 22.4634 11.8511 22.4634H20.8511C21.9556 22.4634 22.8511 21.5679 22.8511 20.4634V11.4634C22.8511 10.3588 21.9556 9.46338 20.8511 9.46338Z"

50

strokeLinejoin="round"

52

animate={isClicked ? 'clicked' : 'unclicked'}

53

variants={clipboardIconVariants}

54

transition={{ duration }}

57

d="M5.85107 15.4634H4.85107C4.32064 15.4634 3.81193 15.2527 3.43686 14.8776C3.06179 14.5025 2.85107 13.9938 2.85107 13.4634V4.46338C2.85107 3.93295 3.06179 3.42424 3.43686 3.04917C3.81193 2.67409 4.32064 2.46338 4.85107 2.46338H13.8511C14.3815 2.46338 14.8902 2.67409 15.2653 3.04917C15.6404 3.42424 15.8511 3.93295 15.8511 4.46338V5.46338"

61

strokeLinejoin="round"

63

animate={isClicked ? 'clicked' : 'unclicked'}

64

variants={clipboardIconVariants}

65

transition={{ duration }}

72

strokeLinejoin="round"

74

animate={isClicked ? 'clicked' : 'unclicked'}

75

variants={checkmarkIconVariants}

76

style={{ pathLength, opacity }}

77

transition={{ duration }}

It might seem dense at first, but you'll notice that it is composed of elements that we've seen individually in the previous sections and examples:

  • variants for the clipboard SVG and the checkmark SVG

1

const clipboardIconVariants = {

2

clicked: { opacity: 0 },

3

unclicked: { opacity: 1 },

6

const checkmarkIconVariants = {

7

clicked: { pathLength: 1 },

8

unclicked: { pathLength: 0 },

  • useMotionValue and useTransform to intertwine the opacity and pathLength values together

1

const pathLength = useMotionValue(0);

2

const opacity = useTransform(pathLength, [0, 0.5], [0, 1]);

Orchestration

For this last part, we will focus on how to orchestrate animations, especially with the two types of orchestration I used the most when building animations:

  • Delays and repetitions: "move to point A, then 2 seconds later move to point B then repeat"

  • Parent-Children: "parent appears first, then the children one after the other at 1-second interval"

Delays and repetition

This is perhaps the first type of orchestration you'll naturally think about when starting to experiment with more complex animations. Framer Motion lets you not only delay when an animation should kick-off but also delay any repetition of that same animation if needed.

I used delays and repetitions to orchestrate some of the micro-animations you can see in my Guide to CI/CD for frontend developers which were the first fairly complex animated components I implemented.

A few orchestration patterns have already been showcased in some of the previous examples out of necessity, but here's a more detailed example for you to play with:

  • you can try to change the repeat type from mirror to loop and observe the subtle change of repetition type.

  • make the animation repeat indefinitely instead of just 3 times.

  • make the initial delay 2s and every repeat delay 1s, you should observe the animation pausing between each repetition.

Parent-Children

A more advanced pattern for orchestration that I recently discovered is what I named "parent-children orchestration". It is pretty useful when you want to delay the animations of some children components in relation to an animated parent component.

Framer Motion gives us the delayChildren option for our transition object to do just that:

Using delayChildren in a transition

25

<motion.div variants={boxVariants} initial="out" animate="in">

28

aria-labelledby="magic wand"

29

variants={iconVariants}

33

<motion.span role="img" aria-labelledby="sparkles" variants={iconVariants}>

On top of that, what if we wanted to not only delay the children as a group but also delay each child based on its siblings, such as, make them appear 1s after their previous sibling appeared. Well, we're in luck, because there's an easy way to do that with the staggerChildren

Using delayChildren and staggerChildren in a transition

27

<motion.div variants={boxVariants} initial="out" animate="in">

30

aria-labelledby="magic wand"

31

variants={iconVariants}

35

<motion.span role="img" aria-labelledby="sparkles" variants={iconVariants}>

What these 2 options exactly do might seem confusing at first. I wished I had some visual examples to really get a grasp on how they worked when I got started. I hope the following visualization will do just that!

In the widget below, you can tweak the values of beforeChildren and staggeredChildren and see how the resulting transition.

I used this type of orchestration to power the list of people who've shared or liked my articles that you can see at the end of each blog post. It's a component that quite a few people like, so I thought I could use it as a little example for you to interact and have fun with:

Conclusion

Wow, we just learned a lot of stuff about Framer Motion! We went from building very basic animations like translations to orchestrate more complex ones involving multiple components and also tie together multiple transitions using useMotionValue and useTransform. You have now learned pretty much everything I know about Framer Motion and can start sprinkling some amazing animations in your own frontend work.

This is my first time trying out this format involving interactive widgets and playgrounds to illustrate what I've learned, let me know what you think! Would you like to see more articles like this one? How would you improve the widgets and examples? I'm always looking to push this blog forward and would love to get some feedback.

Did you come up with some cool animations after going through this guide?

Don't hesitate to send me a message showcasing your creations!

Want to see more?

Here are some other Framer Motion related articles or examples I came up with: