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.

Preset Easings
Bezier Curve Canvas
cubic-bezier(0.25, 0.1, 0.25, 1)
t p P1 P2
Manual Control Points
Motion Preview
400ms
Duration 400ms

Your Custom Curve

ease (reference)

linear (reference)

Export CSS Code

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.
Best Practices for CSS Easing
  • 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.