Skip to content
Animation

Understand easing curves and use them well

What easing curves are, when to use In, Out or InOut and how to apply cubic-bezier values in framer-motion and CSS.

8 min readUpdated: 10 July 2026
Animationframer-motionCSS
Ease-out
cubic-bezier(.22, 1, .36, 1)

An animation only feels natural once its timing is right. Easing curves determine how a motion accelerates and slows down over time. This guide explains the most important curves and how to use them in React and CSS.

The short version
  • Without easing every motion feels mechanical, because in the real world nothing starts and stops at the same speed.
  • Ease-out for anything entering. Ease-in for anything leaving. Ease-in-out for motions with a beginning and an end.
  • The same curve belongs in CSS and in JavaScript, otherwise a site feels inconsistent.
  • Short durations feel more refined than long ones. 0.3 to 0.8 seconds is the useful range.
01

What easing means

Without easing an element moves linearly, at a constant speed. That feels mechanical. In the real world things accelerate and slow down. That is exactly what an easing curve reproduces.

Technically a cubic-bezier curve describes four values that control the path between start and end. It can be drawn as a curve inside a unit square.

Value for CSS
cubic-bezier(0.22, 1, 0.36, 1)
Value for framer-motion
[0.22, 1, 0.36, 1]
Soft0.9 s
No easing0.9 s

Four curves to switch between. Below, two dots run the same distance, once with a curve and once without.

Read the curve from bottom left to top rightTime runs horizontally, distance covered runs vertically. A steep part means fast, a flat part means slow. That is all you need to read one.
02

In, Out and InOut

Ease-In starts slow and speeds up. Good for motions that leave the frame. Ease-Out starts fast and eases out softly. Ideal for elements that enter the frame, because the ending feels calm.

Ease-InOut is symmetric: slow at the start and end, fast in the middle. Suitable for motions that begin and end again, such as a panel that opens and closes.

/* kommt herein */  transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1); /* geht hinaus */transition-timing-function: cubic-bezier(0.55, 0, 1, 0.45); /* auf und zu */transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
The CSS keywords are rough approximations of the three cases.
Commonly seen
  • Ease-in for a menu opening. It starts sluggish and snaps shut at the end.
  • A different curve for every motion, because a different one felt nice at the time.
  • Linear for everything, because it is the browser default.
Works
  • Ease-out for anything appearing. The start is fast, the ending calm.
  • Ease-in only for leaving. Whatever goes away may accelerate.
  • Ease-in-out for states with a there and back, such as a panel.
03

Curves in framer-motion

In framer-motion you pass the curve as a tuple, for example ease: [0.22, 1, 0.36, 1] in the transition. This curve eases out especially softly and suits most fade-ins.

Keep durations short. Between 0.3 and 0.8 seconds most UI motions feel pleasant. Longer times quickly feel sluggish.

0.15 sToo short. You see a jump.
0.5 sThe everyday value for fades.Recommended
1.6 sToo long. You wait for the interface.

The same curve, three durations. The useful range is narrower than it feels while building.

const ease = [0.22, 1, 0.36, 1] as const; <motion.div  initial={{ opacity: 0, y: 12 }}  animate={{ opacity: 1, y: 0 }}  transition={{ duration: 0.5, ease }}/>
The curve goes into the transition as a tuple, not as a string.
Do not confuse duration with distanceIf a motion feels sluggish, the distance is usually too long, not the time. Twelve pixels in half a second feel calm, eighty pixels in the same time feel frantic.

Three curves cover everyday work.

A page with three curves feels ordered, one with twelve feels random. These three are almost always enough.

Soft0.22, 1, 0.36, 1Anything entering
Symmetric0.4, 0, 0.2, 1Open and close, back and forth
Calm0.32, 0.72, 0, 1Long distances across the page
04

Curves in CSS

In CSS you use the same value as transition-timing-function, for example cubic-bezier(0.22, 1, 0.36, 1). This way CSS transitions and JavaScript animations behave consistently.

A curated collection of curves with preview and copy function is available in the library's resources.

:root {    --ease-soft: cubic-bezier(0.22, 1, 0.36, 1);} .card {  transition: transform 0.5s var(--ease-soft);}
Stored once as a variable, the value cannot drift apart.
Only animate opacity and transformBoth run on the GPU. Width, height, top or left trigger a new layout on every frame, and then even the nicest curve will not save it.
05

Curves that almost always work

You do not need a collection of forty curves. Three cover everyday work, and you fetch the rest when a motion really has to be different.

  1. 0.22, 1, 0.36, 1 Eases out very softly. The default choice for fade-ins, cards and anything entering.
  2. 0.4, 0, 0.2, 1 More symmetric and a bit tighter. Good for panels, menus and states that open and close.
  3. 0.32, 0.72, 0, 1 Starts briskly and arrives very calmly. Pleasant for long distances, such as a change across half the page.

More important than the exact numbers is using the same curve everywhere. A page with three curves feels ordered, one with twelve feels random.

A motion you notice is usually too long, not too weak.

06

When a spring fits better

An easing curve has a fixed duration. That is good for fades, but poor for anything reacting to input: an element following the pointer does not know its target yet.

That is what springs are for. In framer-motion you set type: "spring" with stiffness, damping and mass. High stiffness feels fast, high damping feels calm. For subtle motion, low stiffness with high damping is the safe choice.

transition={{  type: "spring",  stiffness: 120,  damping: 20,  mass: 0.6,}}
A spring without wobble: high damping, low stiffness.
Springs wobble if you let themLow damping looks playful in a demo and restless in an interface. For anything that happens often: keep it tight and without overshoot.

A curve when you know the target. A spring when the target comes from input.

Share
Written by
Amelie RoesmannCreative directionLeonie RoesmannDesign engineering

We build websites and web apps at Systra Studios in Münster and put the building blocks from that work here. What you read comes from real projects, not from a brochure.

Systra Studios: web design from Münster

You know the curves.
You do not have to guess the values.

A collection with previews: look at the curve, play it, copy the value. The same value for CSS and for framer-motion.

  • Every curve plays before you take it.
  • One click copies the cubic-bezier value.
  • The same values sit in every component.
Browse easings
Soft0.22, 1, 0.36, 1
Symmetric0.4, 0, 0.2, 1
Calm0.32, 0.72, 0, 1
No easing0, 0, 1, 1
FAQ

Frequently asked questions

cubic-bezier(0.22, 1, 0.36, 1). It starts briskly and arrives very calmly, which is exactly what you expect from something entering the frame. Use it as your default and deviate only when a motion really has to feel different.

Didn't find your question? We're happy to help.

Get in touch