CSS Timing Functions and Cubic-Bezier Explained
This article provides an overview of CSS timing functions, explaining
how they control the rate of change during transitions and animations.
You will learn the mechanics behind the cubic-bezier()
function, how its four coordinates govern acceleration and deceleration
along a curve, and how these mathematical models translate into natural,
physics-driven web motion.
What Are CSS Timing Functions?
CSS timing functions determine how an intermediate property value
transitions from its start state to its end state over a set duration.
Applied via properties like transition-timing-function or
animation-timing-function, they do not alter the total time
an animation takes, nor do they change the starting and ending values.
Instead, they dictate the velocity of the transition throughout
its execution.
Without a timing function specifying varying speed, properties update in a purely mechanical way. By manipulating acceleration, timing functions allow elements to mimic real-world physics, such as inertia, friction, and gravity.
The Coordinate System of
cubic-bezier()
The mathematical foundation of smooth web animations is the cubic
Bézier curve, represented in CSS as
cubic-bezier(x1, y1, x2, y2). This function plots animation
progress on a two-dimensional coordinate plane:
- X-Axis (Time): Represents the progression of time
from
0(0% duration) to1(100% duration). Because time cannot flow backward,x1andx2must always fall within the range of0to1. - Y-Axis (Output Progress): Represents the
progression of the animated property from
0(start value) to1(end value). Unlike the time axis, the Y-axis can extend below0or above1, allowing elements to overshoot their target values for spring or bounce effects.
A cubic Bézier curve relies on four anchor points:
- P0 (0, 0): The fixed starting point in both time and property state.
- P1 (x1, y1): The first control handle, pulling the curve from the start.
- P2 (x2, y2): The second control handle, pulling the curve toward the finish.
- P3 (1, 1): The fixed ending point in both time and property state.
When you write cubic-bezier(x1, y1, x2, y2), you are
specifying the coordinates of control points P1 and
P2.
How the Curve Shapes Acceleration
The slope of the curve at any given point represents the velocity of the animated element:
- Steep Slope: Indicates rapid progression over a short period of time (high speed/acceleration).
- Flat Slope: Indicates minimal progression over time (low speed/deceleration).
- Negative Slope: Occurs when an element moves backward relative to its start or target position.
By pulling the control handles, you reshape the curve and dictate how speed changes:
- Ease-In (
cubic-bezier(0.42, 0, 1, 1)): The curve starts flat and steepens toward the end. The animation begins slowly and accelerates until it abruptly hits the final state, mimicking a falling object. - Ease-Out
(
cubic-bezier(0, 0, 0.58, 1)): The curve starts steep and levels off near the top. The animation begins at maximum speed and gradually decelerates to a stop, mimicking a car braking. - Ease-In-Out
(
cubic-bezier(0.42, 0, 0.58, 1)): The curve starts flat, steepens in the middle, and flattens out at the end. The element accelerates out of its resting state and smoothly decelerates before settling.
Standard Keywords vs. Custom Curves
CSS includes predefined keyword aliases that represent standard cubic Bézier curves:
linear: Equivalent tocubic-bezier(0, 0, 1, 1). The slope is constant, meaning the element moves at the exact same speed from start to finish.ease: Equivalent tocubic-bezier(0.25, 0.1, 0.25, 1). The default timing function; it accelerates quickly and decelerates gradually.ease-in: Equivalent tocubic-bezier(0.42, 0, 1, 1).ease-out: Equivalent tocubic-bezier(0, 0, 0.58, 1).ease-in-out: Equivalent tocubic-bezier(0.42, 0, 0.58, 1).
Custom curves expand beyond these basic presets. By setting
y2 higher than 1 (for instance,
cubic-bezier(0.34, 1.56, 0.64, 1)), the property value
temporarily exceeds 100% before snapping back to
1, creating an elastic overshoot effect. Conversely,
setting y1 below 0 pulls the element in
reverse before it lunges forward.