What a cubic-bezier actually controls
Every CSS transition has a speed curve. ease, linear, ease-in-out are just named shortcuts for one. When none of them feel right, cubic-bezier() lets you draw your own.
The function takes four numbers: cubic-bezier(x1, y1, x2, y2). Those are two control points pulling on a curve that runs from “not started” (bottom-left) to “finished” (top-right). The horizontal axis is time. The vertical axis is progress. Tilt the curve steep early and your element snaps forward then settles. Tilt it late and it creeps, then rushes the finish.
Reading those four numbers cold is rough. So drag the points instead. The handle positions update the value, and a dot above the curve replays the motion on a loop so you feel it, not just read it.
Why drag instead of type
Try typing 0.68, -0.55, 0.27, 1.55 and picturing the result. Hard, right? That one’s an anticipate-and-overshoot: the element backs up slightly, launches past its target, then snaps home. You’d never guess that from the digits.
Here the Y values can run past 0 and 1 on purpose. Pull a handle below the box and the animation winds up before moving. Push it above and the element overshoots and bounces back. That’s how the springy, “designed” motion in good UI gets made, and it’s the part named presets can’t give you.
How to use it
- Drag the two purple handles to bend the curve.
- Watch the dot in the preview strip, it runs your exact timing.
- Nudge the X/Y number fields if you want precise values.
- Hit Copy and paste the
cubic-bezier(...)straight into yourtransitionoranimation.
Drop it in like this: transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);. Same value works in animation-timing-function.
The six presets are starting points, not destinations. ease-out is the safe default for things entering the screen. back-out adds a little confidence to buttons and cards. anticipate is the dramatic one, use it sparingly or your UI feels twitchy.
A few honest notes
Keep durations short. A gorgeous curve at 1.2 seconds still feels slow, and most interface motion lives between 150ms and 400ms. The curve shapes the feel; the duration decides whether people wait on it.
Overshoot easings need room. If an element overshoots into a hard edge or another component, the bounce gets clipped and looks broken instead of bouncy. Give it space or pull the Y values back toward 1.
And remember cubic-bezier can’t do a true multi-bounce (down, up, down, up). The curve only moves forward in time, so you get one overshoot, not a rubber-ball settle. For that you need keyframes.
Questions people ask
What’s the difference between this and the named easings?
ease, ease-in, and friends are just preset cubic-beziers. ease, for instance, is cubic-bezier(0.25, 0.1, 0.25, 1). This tool lets you start from one and bend it until it’s yours.
Can the values go negative or above 1?
The Y values can, and that’s where overshoot and anticipation come from. The X values (time) stay locked between 0 and 1, because time can’t run backward.
Where do I paste the result?
Anywhere a timing function goes: the third part of a transition shorthand, or animation-timing-function on a keyframe animation. The copied string is ready as-is.
Why does my animation look janky with a fancy curve?
Usually it’s animating an expensive property. Stick to transform and opacity, they run on the GPU. Animating width, top, or margin with a springy curve will stutter on slower devices.
Does this work for JavaScript animations too?
The four numbers do. Libraries like GSAP and the Web Animations API accept the same control points, so you can reuse the curve outside CSS.