animation-timing-function works just like the one for transitions, see Timing Function and Delay. It describes the pace of each cycle.
<style>
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(220px); } }
.track { background: #eee; margin: 6px 0; font-size: 12px; }
.dot { width: 26px; height: 26px; border-radius: 50%; background: #1a5276; animation: slide 2.5s infinite alternate; }
.a { animation-timing-function: linear; }
.b { animation-timing-function: ease-in-out; background: #d94a00; }
.c { animation-timing-function: steps(5); background: #27ae60; }
</style>
<div class="track">linear<div class="dot a"></div></div>
<div class="track">ease-in-out<div class="dot b"></div></div>
<div class="track">steps(5)<div class="dot c"></div></div>
Useful values
| Value | Use |
|---|---|
linear | Spinners, progress bars (constant speed) |
ease-in-out | Things that move back and forth |
ease-out | Things arriving |
steps(n) | Jumps: clocks, typing effects, sprite sheets |
cubic-bezier(.2,.8,.2,1) | A custom curve |
The timing applies between keyframes, not to the whole animation
This surprises people. With ease-in-out and keyframes at 0%, 50% and 100%, the easing is applied to each segment (0 to 50, then 50 to 100), so you see a slowdown at the 50% point. For a single smooth curve across the whole animation, use just from and to, or set the timing function inside individual keyframes.
@keyframes move {
0% { transform: translateX(0); animation-timing-function: ease-out; }
100% { transform: translateX(200px); }
}
A spinner needs linear
linear for continuous rotation.