a study of easing
01 · august 2026 · khaled waleed
An easing function bends time. The animation's clock runs 0 to 1 at a constant rate, and the ease maps each tick to how far the value has actually moved. Weight, snap, hesitation: the whole character of a motion lives in that map. CSS ships five bends. GSAP ships a vocabulary. The figures below run on the real engines, so press play on everything.
cubic-bezier(0, 0, 1, 1)cubic-bezier(0, 0, 0.58, 1)the css set
Five keywords, and every one is a single cubic-bezier() in different
clothes. linear leaves the handles on the diagonal; the other four move
them a few tenths. The caption under each figure shows the four numbers its keyword
stands for. Past the keywords you write your own numbers with cubic-bezier(), hold frames with steps(), or, since 2023,
hand the browser a list of points with linear() and let it connect the
dots.
cubic-bezier(0.25, 0.1, 0.25, 1)cubic-bezier(0.42, 0, 1, 1)cubic-bezier(0, 0, 0.58, 1)cubic-bezier(0.42, 0, 0.58, 1)steps(5)linear(0, 0.0625, 0.25, 0.5625, 1, 0.8125, 0.75, 0.8125, 1, 0.9375, 1, 1)The last figure is a bounce squeezed into 12 generated points. Keep the corners in mind; they come back at the end.
the ceiling
One cubic segment can change direction twice, and that is the whole budget. Push a
y handle past 1 and you buy a single overshoot, the spring fake below. A real bounce
turns six times. An elastic settle keeps turning until it dies out. No four numbers
draw either shape, so past this line CSS needs a generated linear() list, and somebody has to generate it.
cubic-bezier(0.34, 1.56, 0.64, 1)The dashed blue curve is elastic.out(1, 0.3), the shape the cubic is
chasing. It catches the first swing and misses the rest.
the gsap shelf
GSAP names its curves and grades them. sine is the gentlest; power1 through power4 raise the same shape by degrees; expo and circ sit at the steep end. back overshoots, elastic rings, bounce lands like a dropped
ball. Every family conjugates three ways, and the suffix is the design decision: .out for arrivals, .in for exits, .inOut for
moves between rest states. The name carries the intent. ease: "power2.out" reads at a glance; cubic-bezier(0, 0, 0.58, 1) sends the next reader off to plot it.
GSAP will not even default to a straight line. Tweens fall back to power1.out, because constant speed is the one thing almost nothing in
the physical world moves at.
"sine.out""power2.out""power4.out""expo.out""circ.out""back.out""elastic.out""bounce.out"tuning
When a bezier needs more overshoot, you write four new numbers and squint at the
plot. When back needs more, you write back.out(2.5).
Parameters carry the adjustment: overshoot for back, amplitude and
period for elastic, a count for steps. Same name,
different temperament.
ease: "back.out(1.7)" the dotted curve holds the family default
the transplant
Here is elastic in CSS, honestly. The one-cubic spring fake above was the best four
numbers can do. The faithful version is linear() fed 80 stops, and the
80 stops come from sampling GSAP's own function:
transition-timing-function: linear(0, 0.116, 0.2762, 0.462, 0.6561, 0.8434, 1.0117, 1.1521, 1.2591, 1.3305, 1.3668, 1.3713, 1.3487, 1.3049, 1.2465, 1.18, 1.1114, 1.0459, 0.9877, 0.9398, 0.9038, 0.8805, 0.8694, 0.8694, 0.8786, 0.895, 0.9163, 0.94, 0.9642, 0.987, 1.0071, 1.0235, 1.0355, 1.0431, 1.0464, 1.0459, 1.0422, 1.0361, 1.0284, 1.0199, 1.0114, 1.0034, 0.9965, 0.991, 0.9869, 0.9845, 0.9835, 0.9839, 0.9854, 0.9876, 0.9904, 0.9934, 0.9964, 0.9992, 1.0016, 1.0034, 1.0048, 1.0056, 1.0058, 1.0056, 1.0051, 1.0042, 1.0032, 1.0022, 1.0011, 1.0002, 0.9993, 0.9987, 0.9983, 0.998, 0.9979, 0.998, 0.9982, 0.9986, 0.9989, 0.9993, 0.9997, 1, 1.0003, 1); That string renders the right motion. It is also unreadable, untunable by hand, and authored by the library it stands in for. Change the period and you regenerate all 80 numbers; in GSAP you edit one.
- gsap
ease: "elastic.out(1, 0.3)" - css, one cubic
cubic-bezier(0.34, 1.56, 0.64, 1) - css, linear()
linear(0, 0.116, 0.2762, … 77 more)
the verdict
For interface furniture, CSS is enough and often better. A hover tint, a menu slide, a transform the compositor can run off the main thread with no JavaScript on the page: the five keywords and a hand-tuned bezier earn their keep there.
GSAP's eases win the moment motion is designed. They are named and parameterized,
so ease: "elastic.out(1, 0.3)" records the decision in the code. They
cover shapes one cubic never will. And each ease is a plain function of progress,
so the same curve drives a transform today, a scroll position tomorrow, a WebGL
uniform after that, then plays backwards inside a timeline without a rewrite. cubic-bezier() styles one property on one element in one direction,
and that is the gap the four numbers never close.
The museum next door changes rooms on two cubic-beziers; that job is CSS-sized. Every figure here that rings or bounces runs on GSAP, because CSS still cannot draw those curves on its own.
method: css curves are plotted from the spec's cubic-bezier math, gsap curves are sampled from gsap.parseEase (gsap 3.15). the dots run on the engines themselves: css transitions drive the pencil lanes, gsap tweens drive the blue. reduced motion is honored; demos jump to their endings and the curves stay still ink.