Understanding cubic-bezier
Time, but with feeling.
A four-number recipe that turns a linear interpolation into something that moves like a real object.
What an easing curve does.
A CSS transition or animation runs from 0 to 1 over its duration. The easing function maps that progress to a different value before applying it. If the function returns 0.5 at time 0.5, the animation is linear. If it returns 0.05 at 0.5, the animation creeps for the first half then dashes through the second — an ease-out. The function is what makes the motion feel weighty, springy, lazy or sharp.
cubic-bezier(x1, y1, x2, y2)
Two control points.
A cubic Bézier curve is defined by four points: a start (locked at 0,0), an end (locked at 1,1), and two control points you choose. The control points pull the curve toward themselves without ever being on it. CSS lets you set each control point's x in [0, 1] and y in any value (negative y-values overshoot the start; values above 1 overshoot the end). That's where bouncy "back-and-then-settle" easings come from.
The named keywords.
CSS ships four named functions that all map to specific cubic Béziers. ease is cubic-bezier(0.25, 0.1, 0.25, 1). ease-in drags at the start, ease-out at the end, ease-in-out at both. None of them is wrong, but almost no production system actually uses them — designers tune their own curves to feel like the brand. Material Design's "standard" curve is cubic-bezier(0.4, 0.0, 0.2, 1), sharper and flatter at the ends than CSS's ease.
Ease-out almost always wins.
For UI motion — a panel sliding in, a button springing back, a card arriving — ease-out feels right because it matches how real objects settle: fast at the start, slower as they reach rest. Linear motion looks robotic. Ease-in (slow start, fast end) feels like someone's late. Ease-out is the safe default; reach for ease-in-out for symmetric two-state transitions (a modal opening and closing on the same path).
Overshoot and bounce.
Push the second control point's y past 1 and the curve overshoots before settling — that's the spring effect every modern UI library has. The back easings in older easing libraries are exactly this: a y2 just over 1, just enough to feel alive without flailing. Real spring physics (the linear() function with a long sample list, or actual spring solvers) gives a more nuanced feel; cubic- Bézier is the cheap and good-enough approximation.
Pair with the right duration.
Even a perfect curve can feel wrong at the wrong duration. UI interactions that need to feel snappy live in 150–250 ms. Larger transitions (a full-page modal, a route change) deserve 300–400 ms. Anything past 500 ms reads as slow. And always honour prefers-reduced-motion — for users who set it, the most honest move is to compress every transition to under 150 ms or skip it entirely.
Read next