Shots in this scene
linear() and Custom Curves
In one line
linear() takes a list of points and draws straight lines between them. With enough points it can copy any curve, including a bounce or a spring, which cubic-bezier() cannot. It works in every current browser, but older ones ignore it, so give it a fallback.
Think of it like this
Connect-the-dots. With four dots you draw a rough bend. With forty dots, joined by short straight lines, the picture looks smooth and can show a wiggle that four dots never could. linear() is connect-the-dots for an easing curve.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- linear()
- A CSS easing made of a list of points joined by straight lines. Not to be confused with the keyword
linear. - sampling
- Reading a function's value at evenly spaced moments to turn it into a list of numbers.
- bounce
- A curve that reaches the end value, goes back, and reaches it again, several times.
- @supports
- A CSS rule that applies its block only if the browser understands the property and value in its test.
- fallback
- A simpler declaration that an older browser uses when it cannot understand the new one.
Step by step
01Press Drop
Run "Bounce: 4 points, 24 points, a fallback" and press Drop. Three balls fall 78 px. The first (4 points) drops with a smooth slowdown and no bounce. The second and third (24 points) bounce.
02Step to 338 ms
Pause, press Drop, step to 338 ms. The 24-point balls are at 75.6 px, just touching the floor. The 4-point ball is at 48.4 px. At 563 ms the 24-point balls are bouncing back at 62.3 px while the 4-point ball is at 67.9 px and still going down.
03Read the console
The console says linear() supported: true and shows what the browser refuses: one point, an empty list. The 4-point ball's computed value is linear(0 0%, 0.473 25%, 0.766 50%, 0.973 75%, 1 100%).
04Build one from a function
Run "A spring, sampled into linear()". It samples a damped spring into 30 points: the console says it overshoots to 1.284 and the string is 214 characters. Press Rebuild with 8 points: now the peak is 1.209 and the string is 61 characters.
Try it yourself
- 1
Pretend to be an old browser
Change
@supports (transition-timing-function: linear(0, 1))tolinear(0)(which is invalid). The block is skipped, as in an old browser. Press Drop: the third ball no longer bounces; it lands with a soft ease-out (70.3 px at 338 ms, 77.0 px at 563 ms, 78 px at the end). - 2
Fewer points
In "A spring" press Go, step to 150 ms: the box is at 229.1 px (the exact curve gives 230.8). Rebuild with 8 points and compare: the whole curve is rougher and peaks lower, at 1.209 instead of 1.284 (217.6 px instead of 231 px).
Code & diagrams
Try it: interactive
Springs as linear()
Pick the spring curve, change its stiffness and damping, and press Play. Read the linear() text the lab prints. Make a spring that overshoots, then one that does not.
Three balls with the same 900 ms drop. The left one has a 4-point list, the others a 24-point bounce, the last wrapped in @supports with a soft cubic-bezier before it. The console prints what CSS.supports says about a few lists.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
linear() supported: true
one point: false
empty: false
stops with %: true
two stops on one value: true
few: linear(0 0%, 0.473 25%, 0.766 50%, 0.973 75%, 1 100%)The easing string is built by JavaScript from a damped-spring formula. Press Go, step to 150 ms, then rebuild with 8 points and compare.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
30 points: overshoot to 1.284, string is 214 charactersBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Too few points
In "Bounce" replace the 24-point list on the second ball with linear(0, 0.473, 0.766, 0.973, 1), or just look at the first ball.
Break #2
The list does not end at 1
Replace the second ball's list with linear(0, 0.5, 0.9).
Myth vs fact
Myth
linear() is the same as the keyword linear.
Fact
The keyword is a straight line from 0 to 1. The function takes your points and can draw any shape; a list linear(0, 1) is the same as the keyword.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
linear()is accepted wherever a CSS easing is:animation-timing-function, and theeasingoption of the Web Animations API. One string serves both.
Remember this
- 1
The problem this solves:
cubic-bezier()draws one smooth bend with at most one overshoot. It cannot bounce three times, and it cannot be a spring that wobbles and settles. For those you need to say the exact progress at many moments. - 2
The syntax.
linear(0, 0.25, 1)lists output values. With no positions they are spaced evenly: here at 0%, 50% and 100%. You may give a position,linear(0, 0.5 30%, 1), and a value may hold for a stretch with two positions,1 20% 60%. The browser draws straight lines between the points. Its computed value always lists a percent for every point, as the console shows. - 3
More points, truer curve. The straight lines are only an approximation. In the first example the same bounce is drawn with 4 points and with 24: at 338 ms the 24-point ball has hit the floor (75.6 px of 78) and the 4-point ball is still falling (48.4 px). A typical generated bounce or spring has 30 to 60 points; each costs a few characters.
- 4
Sample a function. You rarely type the numbers. You write the maths of the motion (a bounce, a damped spring
1 − e^(−6t)·cos(14t)), take its value at evenly spaced moments, round to three decimals and join them into a string. The second example does this in 6 lines. - 5
A spring in linear() has a fixed shape. The curve overshoots to 1.284 (231 px on a 180 px move: 51 px past the target) and settles within the duration you give it. It does not know about velocity: if the user interrupts it, the next animation starts from rest. True springs that keep their speed come in Phase 9.
- 6
Start at 0 and end at 1. If the last point is not 1, the animation ends there, and then the element jumps to its real end value. In the break-it below, a list ending at 0.9 stops at 70.1 px and snaps to 78 px in the last frame.
linear(0)(one point) andlinear()(none) are invalid. - 7
Support and fallback.
linear()arrived in Chrome 113, Firefox 112 and Safari 17.2, so a few percent of visitors (check caniuse for today's figure) still use a browser without it. Such a browser that does not understand it throws the declaration away. Write a plain declaration first (acubic-bezierwith a similar feeling), then override inside@supports (transition-timing-function: linear(0, 1)). In an old browser the ball lands softly instead of bouncing, and nothing breaks. A bounce is decoration: leave it out for reduced motion.
Explain it without notes
Why can linear() make a bounce when cubic-bezier() cannot?
How would you give an old browser a good result when you use linear()?
What happens if the last point of a linear() list is 0.9?
Practice
Write a linear() list for a single overshoot of 1.1 that settles at 1 with 6 points, and say what the first and last points must be.
Change the spring example so the sampling uses 12 points and a decay of 4 instead of 6. What happens to the overshoot?
Done when you can
You can write a
linear()list with and without positionsYou can sample a function into one and say how many points it needs
You can wrap it in
@supportswith a fallbackYou know it must start at 0 and end at 1