CSS Cubic Bezier Generator
Design custom CSS easing curves by dragging control handles on an interactive Bezier canvas. Preview motion in real-time, compare against standard easings, and export perfect cubic-bezier() transition code.
Your Custom Curve
ease (reference)
linear (reference)
How CSS Cubic Bezier Easing Works: The Mathematics of Motion
A cubic Bezier curve is defined by the polynomial formula B(t) = (1-t)³P0 + 3(1-t)²tP1 + 3(1-t)t²P2 + t³P3, where t is a parameter ranging from 0 to 1 and P0 through P3 are the four control points. In CSS, the two anchor points are always fixed at (0,0) and (1,1) representing animation start and completion. The two user-configurable control points — expressed as (x1, y1, x2, y2) in the cubic-bezier() function — define the curve's shape. The x values (constrained to 0 to 1) control the timing pacing, while the y values (which can exceed 0 to 1) control the output progress, enabling overshoot effects.
The CSS browser engine evaluates this curve for every rendered frame during a transition. For a 400ms transition at 60fps, the engine calls the timing function approximately 24 times, each time computing the interpolated progress value at that frame's time position. This computed progress value then maps directly to the interpolated CSS property value — for a color transition from red to blue, a progress of 0.5 means a 50% mix. The curve's slope at any point represents the instantaneous speed: steep slopes mean fast change, flat slopes mean the property is barely moving.
Before & After: Linear vs Custom Bezier Easing
❌ Before — Robotic Linear Motion
.card:hover {
transform: translateY(-8px);
transition: transform 300ms linear;
/* Feels mechanical and unnatural */
} ✅ After — Physics-Inspired Spring
.card:hover {
transform: translateY(-8px);
transition: transform 400ms
cubic-bezier(0.34, 1.56, 0.64, 1);
/* Overshoots slightly, then settles */
} CSS Easing Keyword Reference
| CSS Keyword | cubic-bezier() Equivalent | Best Use Case |
|---|---|---|
| ease | 0.25, 0.1, 0.25, 1.0 | General UI transitions, default choice |
| ease-out | 0, 0, 0.58, 1.0 | Entering elements — feels fast and controlled |
| ease-in | 0.42, 0, 1.0, 1.0 | Exiting elements — feels intentional |
| ease-in-out | 0.42, 0, 0.58, 1.0 | Looped animations, continuous motion |
| Spring | 0.34, 1.56, 0.64, 1 | Snappy hover states, energetic interactions |
| Material | 0.4, 0, 0.2, 1 | Material Design standard motion |
Common Mistakes & Troubleshooting
- ✕Using ease-in for entering elements: ease-in starts slow — exactly the wrong pacing for an element entering the screen. Use ease-out for entries (fast start, graceful deceleration) and ease-in for exits (slow start, fast departure).
- ✕X1 or X2 values outside 0 to 1: The CSS spec mandates X values between 0 and 1 inclusive. Setting them outside this range causes the browser to silently ignore the declaration and fall back to linear. Y values, however, can freely exceed 0 to 1 for overshoot.
- ✕Overusing spring easings: Overshoot effects feel energetic for small interactive elements but become nauseating for large full-screen transitions. Reserve spring/bounce easings for micro-interactions like buttons and chips — not page transitions.
- Define a set of 3 to 5 custom easing tokens as CSS variables (--ease-enter, --ease-exit, --ease-spring) and apply them consistently across all components.
- Use ease-out for elements entering the viewport and ease-in for elements leaving — this mirrors the natural physics of real-world objects.
- Keep transition durations between 100ms and 400ms for UI interactions — longer durations feel sluggish on routine interactions.
- Reserve overshoot cubic-bezier values (Y1 or Y2 greater than 1) for small interactive elements like buttons, tags, and icons — never for full-page transitions.
- Prefer cubic-bezier over linear() for broad browser compatibility — linear() only reached full cross-browser support in late 2023.
Frequently Asked Questions
What is a cubic Bezier curve in CSS animation?
A cubic Bezier curve is a parametric curve defined by four points: two fixed anchor points at (0,0) and (1,1) that represent the start and end of the animation timeline, and two user-adjustable control points (P1 and P2) that shape the curve's trajectory between them. In CSS, the cubic-bezier() timing function uses only the X and Y coordinates of these two control points — expressed as cubic-bezier(x1, y1, x2, y2) — to compute the speed profile of any CSS transition or animation at each point in time. The X axis represents time progression from 0 to 1, while the Y axis represents animation completion from 0 to 1, meaning Y values outside this range produce spring-overshoot effects.
How do the built-in CSS easing keywords relate to cubic-bezier values?
Every CSS easing keyword is a named alias for a specific cubic-bezier() function value. The keyword ease translates to cubic-bezier(0.25, 0.1, 0.25, 1.0), which starts slow, peaks in speed at about 30% of the duration, then decelerates. ease-in maps to cubic-bezier(0.42, 0, 1.0, 1.0), accelerating throughout. ease-out maps to cubic-bezier(0, 0, 0.58, 1.0), decelerating throughout. ease-in-out maps to cubic-bezier(0.42, 0, 0.58, 1.0), a symmetric S-curve. The linear keyword is cubic-bezier(0, 0, 1, 1). Understanding these underlying values lets you design custom easings that feel like refined, more physically natural versions of the built-in keywords.
What does it mean when a cubic-bezier Y value is outside the 0 to 1 range?
When a cubic-bezier control point Y value is set below 0 or above 1, the animation overshoots its target — it temporarily goes beyond the start or end value before settling at the final position. This produces what designers call "spring" or "elastic" easing, where an element appears to bounce or snap past its destination before returning. For example, cubic-bezier(0.34, 1.56, 0.64, 1) drives Y1 above 1, causing the element to exceed its final position by about 15% before settling — a popular effect for button hover lift animations and modal entrance transitions.
Why should CSS transitions use cubic-bezier instead of linear timing?
Linear timing advances the animated property at a constant rate from start to finish, producing a robotic, mechanical motion that is immediately perceived as artificial by human viewers. Human perception is calibrated to physically natural motion — objects accelerate due to force and decelerate due to friction. Easing curves that mirror these physics, particularly ease-out for incoming elements (decelerating, as if stopping) and ease-in for exiting elements (accelerating, as if being dismissed), dramatically improve the perceived quality and craftsmanship of a UI. Research from Google's Material Motion team found that ease-out transitions feel 40% faster than linear ones of the same duration, even though the clock time is identical.
How do CSS cubic-bezier curves relate to JavaScript animation libraries?
Animation libraries like GSAP (GreenSock), Framer Motion, and Motion One all use Bezier curve mathematics internally to compute their easing functions. GSAP's Power1, Power2, and Power3 ease families are polynomial approximations of Bezier curves of increasing steepness. Framer Motion's spring() easing system is a physics simulation that can be expressed as an approximated cubic-bezier for CSS transitions. Because these libraries operate in JavaScript and animate DOM properties using requestAnimationFrame, they have full access to the same curve mathematics but can also apply time-varying easings and spring physics that pure CSS transitions cannot express.
What is the difference between transition-timing-function and animation-timing-function in CSS?
Both properties accept the same cubic-bezier() value and apply it to the animated property's progress over time. However, they operate in distinct contexts. transition-timing-function applies to CSS transitions triggered by property value changes (via class toggles or JavaScript style updates), and the easing is applied once per transition. animation-timing-function applies per iteration of a @keyframes animation, controlling the speed curve within each keyframe interval — not across the entire animation duration. This distinction matters for multi-keyframe animations: setting a cubic-bezier on animation-timing-function means the curve is applied independently between each adjacent pair of keyframes.
What is the CSS linear() function introduced in 2023?
The CSS linear() function, now supported in Chrome 113+, Firefox 112+, and Safari 17.2+, is a new timing function that accepts multiple stop points to define arbitrary easing curves with sharp turns, step-like behavior, and physically simulated spring effects — all impossible with a single cubic-bezier. Unlike cubic-bezier() which only supports smooth S-curves, linear() takes a series of output values at optional time positions (e.g., linear(0, 0.5 25%, 1 75%)) allowing stepwise, bounce, and complex spring physics to be expressed natively in CSS without JavaScript. The Jake Archibald linear() generator is the primary tool for creating these new easing specifications.
Related CSS Design Tools
Build tactile Soft UI shadow effects
Interactive 3D perspective styling canvas
Animated button designer with hover effects
Polygon and geometric clip masks
Responsive CSS ratio export
Easing curve designer — you are here