A valid CSS cubic-bezier() easing declaration is written as cubic-bezier(x1, y1, x2, y2) where the curve always starts at progress point (0, 0) and always ends at (1, 1), with the four numbers you supply defining the two intermediate control points that shape how the animated value accelerates and decelerates over time. To generate a CSS cubic bezier that animates correctly in the browser, you need four finite numbers that satisfy one strict rule from the W3C CSS Easing Functions Level 1 specification: the x1 and x2 coordinates must each lie inside the closed 0-to-1 range, because they describe input-time positions, while y1 and y2 describe output progress and may travel further to create anticipation or overshoot. A practical way to produce a standards-compatible declaration is to load the CSS Cubic Bezier Generator, start from one of the five standardized keyword presets, and then adjust the four controls while watching a live preview of the motion.
The cubic-bezier() function is the timing curve used by both the CSS transition-timing-function property and the CSS animation-timing-function property, so a single generated declaration will drive any transition or keyframe animation that accepts a timing function. Because the function only describes how progress maps to time, the declaration itself is short — one line, four numbers, no animation engine and no keyframes.

Anatomy of a CSS cubic-bezier() Function
Every cubic-bezier() easing is a parametric curve from (0, 0) to (1, 1) with two intermediate control points. The x axis of the curve represents elapsed input time as a fraction of the animation duration, and the y axis represents how far the animated value has progressed. Reading the curve at x = 0.5, for example, tells you where the animated element sits when half the duration has passed.
| Coordinate | Role | Required Range | What Happens Outside the Range |
|---|---|---|---|
| x1 | Horizontal position of the first control point | 0 to 1 inclusive | Declaration is invalid; CSS rejects it |
| y1 | Vertical pull of the first control point | Finite, typically −10 to 10 | Can create anticipation below 0 or overshoot above 1 |
| x2 | Horizontal position of the second control point | 0 to 1 inclusive | Declaration is invalid; CSS rejects it |
| y2 | Vertical pull of the second control point | Finite, typically −10 to 10 | Can create anticipation below 0 or overshoot above 1 |
The two x coordinates are the most common source of an invalid declaration. If either x1 or x2 falls outside the closed 0-to-1 range, the entire cubic-bezier() value is treated by the browser as malformed and the property falls back to its initial value, which is ease. The two y coordinates have no such hard limit, so designers regularly use a y value below 0 or above 1 to produce springy, expressive timing — provided the resulting motion still reads as intentional.
A Visual Generator vs Guessing Numbers: Which Works Better
Hand-tuning four floating-point numbers and then mentally visualizing how they will bend a curve is slow and error-prone. A visual generator solves three concrete problems at once: it constrains x inputs to the valid CSS range so you cannot paste an invalid value, it solves the inverse problem of "what progress have we reached at this fraction of time" using Newton iterations plus bounded bisection, and it shows the resulting motion on a moving element before any code leaves the page.
The CSS Cubic Bezier Generator runs entirely in the browser, so no curve values, control coordinates, or interaction data are uploaded to an animation service. The four input fields update the curve, the numeric sample table, and the running preview in the same frame, which makes it fast to compare a default easing against a custom one.
Generate a CSS Cubic Bezier in Three Steps
- Choose a starting preset or enter custom coordinates. Click any of the five keyword buttons — Linear, Ease, Ease In, Ease Out, or Ease In Out — to load the standardized four-number curve defined by W3C CSS Easing Functions Level 1, or type values directly into the x1, y1, x2, and y2 fields. The generator constrains the x inputs to the valid 0-to-1 CSS range and accepts finite y values across a wide band so you can explore overshoot without breaking the syntax.
- Review the graph, sample table, and preview motion. Watch the parametric curve plotted on the square chart, read the five numeric samples that show the y output at x = 0, 0.25, 0.5, 0.75, and 1, and click Run preview to watch a circle ease between two positions over a 900-millisecond transform transition. The numeric table uses Newton iterations followed by bisection to find the curve parameter that produces each requested x coordinate, then evaluates y — this is the correct way to read a Bézier curve, and it answers a question the curve diagram alone cannot.
- Copy the complete CSS declaration. Once the timing reads right, click Copy CSS to write the full transition-timing-function: cubic-bezier(x1, y1, x2, y2); line to the clipboard, including its semicolon. Paste it into your stylesheet and test it on the real property, distance, and duration you plan to ship.
The Five Standardized Keyword Mappings
The keyword buttons do not output the keyword itself. Every press loads the four standardized control coordinates behind that keyword, so the visible declaration always exposes all four numbers and you can record, compare, or tweak them without hidden defaults. The table below lists each keyword and the four-number curve defined by the W3C specification.
| CSS Keyword | Equivalent cubic-bezier() | Typical Feel |
|---|---|---|
| linear | cubic-bezier(0, 0, 1, 1) | Constant speed, no easing |
| ease | cubic-bezier(0.25, 0.1, 0.25, 1) | Default, gentle start and finish |
| ease-in | cubic-bezier(0.42, 0, 1, 1) | Slow start, fast finish |
| ease-out | cubic-bezier(0, 0, 0.58, 1) | Fast start, slow finish |
| ease-in-out | cubic-bezier(0.42, 0, 0.58, 1) | Slow both ends, fast middle |
As a worked reading example, take the ease-in-out declaration cubic-bezier(0.42, 0, 0.58, 1). At input time x = 0.5 the solver finds the curve parameter whose x coordinate is 0.5 and then evaluates y. The result lands at y = 0.5 as well, because the easing is symmetric — but the path the curve takes from (0, 0) to (1, 1) is what gives ease-in-out its characteristic acceleration in the middle and deceleration at both ends. For the linear declaration cubic-bezier(0, 0, 1, 1), the solver produces the obvious y = 0.5 at x = 0.5 because the curve is the identity line.
Reading the Sample Table and Preview Motion
The sample table shows five y values, one for each of the five x positions 0, 0.25, 0.5, 0.75, and 1. The middle three values are the ones that distinguish one easing from another: at x = 0 and x = 1 every valid cubic-bezier() curve passes through y = 0 and y = 1 by definition, so the table only varies in between. If a sample reads below 0 or above 1 in the middle, the curve produces anticipation or overshoot — useful for expressive motion, but worth checking on the moving preview to confirm it does not surprise the user.
The preview is a 900-millisecond transform transition on a single circle. Repeated clicks let you compare forward and reverse motion in the same easing. The preview demonstrates timing, not production performance: a real component can feel different when the distance, duration, property, rendering cost, input device, or surrounding motion changes. Treat the preview as a sanity check for shape and rhythm, then test the final declaration in its actual interface.
Before You Paste: Validation and Accessibility Checks
A declaration can be technically valid and still feel wrong in a real interface. Run through four quick checks before you ship the easing.
- Confirm x1 and x2 stay inside the 0-to-1 range. The generator already enforces this, but if you later hand-edit the numbers in your stylesheet, a value such as 1.2 will silently invalidate the whole property. The browser will fall back to ease rather than flagging the invalid input loudly.
- Inspect extreme y values on the preview. Overshoot above 1 can push elements past their intended resting position, which may reveal clipped content, push controls outside a container, or appear to reverse direction briefly. Anticipation below 0 has the same risk in the opposite direction. Both are valid CSS; neither is automatically a bug, but both deserve a visual check.
- Test the easing on the real property and distance. A 900-millisecond preview on a small transform is not the same as a 200-millisecond hover state or a 2-second modal entrance. The shape of the easing is invariant; the perceived motion depends on the distance and duration you pair it with.
- Respect reduced-motion preferences. The CSS Cubic Bezier Generator outputs only the timing function and does not decide whether animation is essential. Wrap expressive eases inside a @media (prefers-reduced-motion: no-preference) block, or pair them with a no-animation fallback so users who opt out of motion still receive the state change.
The generator also stays narrowly focused on the timing function. It does not produce keyframes, spring physics, linear() stop lists, steps() timing, duration, delay, iteration count, or a full transition shorthand. That scope is intentional: the shorter and more predictable the output, the easier it is to audit, copy between files, and version-control alongside the rest of your stylesheet. For a deeper look at why x and y play by different rules, see Can y1 or y2 Leave the 0–1 Range in CSS cubic-bezier()?, and for guidance on applying the resulting declaration to a custom animation, see How to Use Cubic Bezier CSS for Custom Easing. For a fourth reference on the syntax and keyword mappings, the MDN page for cubic-bezier() documents browser-oriented examples alongside the W3C specification.