animation-timing-function maps elapsed progress to value progress between keyframes. It changes pacing; ease-in is not a complete gravity or bounce simulation.
Compare linear and ease-in
Both squares travel for two seconds. Linear advances evenly; ease-in starts slowly and accelerates toward the end.
HTML and CSS
HTML
<input class="run" id="run" type="checkbox" /><label for="run"
>Run the demonstration; uncheck to reset</label
>
<div class="stage">
<p>Linear</p>
<div class="box" aria-hidden="true"></div>
<p>Ease-in</p>
<div class="box eased" aria-hidden="true"></div>
</div>
CSS
@keyframes travel {
from {
transform: translateX(0);
}
to {
transform: translateX(100px);
}
}
.stage {
background: #eff6ff;
padding: 1rem;
}
.box {
width: 50px;
height: 35px;
background: #2563eb;
margin-block: 0.5rem;
}
label {
display: inline-block;
padding: 0.75rem;
}
.run:checked ~ .stage .box {
animation: travel 2s forwards;
animation-timing-function: linear;
}
.run:checked ~ .stage .eased {
animation-timing-function: ease-in;
}
@media (prefers-reduced-motion: reduce) {
.run:checked ~ .stage .box {
animation-name: none;
}
}
Edit HTML or CSS to update the preview as you type. Copy code snippet copies the selected tab. Preview spacing and font defaults are not included.
Advance through four steps
Steps(4,end) holds the progress and jumps at each interval’s end. The one-second total duration remains unchanged.
HTML and CSS
HTML
<input class="run" id="run" type="checkbox" /><label for="run"
>Run the demonstration; uncheck to reset</label
>
<div class="stage"><div class="box" aria-hidden="true"></div></div>
CSS
@keyframes travel {
from {
transform: translateX(0);
}
to {
transform: translateX(100px);
}
}
.stage {
background: #eff6ff;
padding: 1rem;
}
.box {
width: 50px;
height: 35px;
background: #2563eb;
margin-block: 0.5rem;
}
label {
display: inline-block;
padding: 0.75rem;
}
.run:checked ~ .stage .box {
animation: travel 1s forwards;
animation-timing-function: steps(4, end);
}
@media (prefers-reduced-motion: reduce) {
.run:checked ~ .stage .box {
animation-name: none;
}
}
Edit HTML or CSS to update the preview as you type. Copy code snippet copies the selected tab. Preview spacing and font defaults are not included.
Values and defaults
The initial value is ease and the property is not inherited. Keywords include linear, ease, ease-in, ease-out, and ease-in-out. Cubic-bezier(x1,y1,x2,y2) requires x1/x2 in 0–1; y values can overshoot. Steps() supplies a valid count and jump position. Newer linear() piecewise stops have separate support.
Easing normally applies between successive keyframes, not once across an arbitrarily segmented entire animation. An easing declaration in a keyframe controls the following segment; one on the final keyframe has no next segment to affect. Reverse direction also reverses easing.
Common mistakes
Timing alone cannot create a named animation. A slow-to-fast curve is not necessarily comfortable, and “smooth” is not a substitute for reduced-motion support. Comma-separated functions map to names and shorter lists repeat. A later shorthand resets easing.
Learn animation-direction, transition-timing-function, and animation-duration.
The demonstrations are stationary when prefers-reduced-motion:reduce is active. Their code remains available for inspection.
Sources and browser support
MDN: animation-timing-function describes the syntax and links to the specification and compatibility data. Check individual values in that table when supporting older browsers.