CSS animation-timing-function Property

This property sets the internal pace of an animation by defining its speed curve over the specified duration.

selector { animation-timing-function: value; }
ease Starts slow, speeds up in the middle, and finishes slowly.
linear Maintains a constant speed from start to finish.
ease-in Starts at a slow pace and accelerates until the end.
ease-out Starts at a fast pace and decelerates until the end.
ease-in-out Starts and ends with a slow pace, speeding up only in the middle.
step-start Jumps immediately to the final state at the beginning of the animation.
step-end Maintains the initial state until the animation duration is finished.
steps(int, start|end) Divides the animation into a specific number of equal intervals.
cubic-bezier(n,n,n,n) Defines a custom speed curve using four numeric values between 0 and 1.

Code Examples

A basic example showing a red ball sliding back and forth using an ease-in-out timing function for smooth acceleration and deceleration.

<style>
.stage {
  width: 100%;
  height: 100px;
  background: #eeeeee;
}
.ball {
  width: 50px;
  height: 50px;
  background: #ff0000;
  border-radius: 50%;
  animation: slide 3s infinite;
  animation-timing-function: ease-in-out;
}
@keyframes slide {
  from { margin-left: 0%; }
  to { margin-left: 90%; }
}
</style>
<div class="stage">
  <div class="ball"></div>
</div>

An advanced example using a button to dynamically change the timing function to a stepped interval using JavaScript.

<style>
.loader-bar {
  width: 0%;
  height: 20px;
  background: #00ff00;
  animation: load 5s forwards;
}
@keyframes load {
  to { width: 100%; }
}
</style>
<div style="width: 300px; border: 1px solid #333333;">
  <div id="progress" class="loader-bar"></div>
</div>
<button onclick="applySteps()">Apply Steps</button>
<script>
function applySteps() {
  const bar = document.getElementById("progress");
  bar.style.animationTimingFunction = "steps(10, end)";
  bar.style.backgroundColor = "#0000ff";
  console.log("Timing function changed to 10 steps via JavaScript.");
}
</script>

Pro Tip

You can use the "steps()" function to handle sprite-sheet animations. By setting the number of steps to match the number of frames in your image strip, you can create a perfect frame-by-frame animation without any blurry sliding between the frames. It is also a great way to create a retro "digital clock" feel for text changes.

Deep Dive

Think of this property as the driver of a car. While the duration tells you how long the trip takes, the timing function determines if the driver floors the gas at the start, cruises at a steady speed, or slams the brakes at the end. It maps the passage of time to the progression of the animated property. By default, "ease" is used because it feels more natural to the human eye; objects in the real world rarely start or stop instantly at full velocity. The property uses a mathematical cubic Bezier curve to calculate the intermediate values between keyframes. When you use keywords like "ease-in", you are actually using shorthand for specific Bezier coordinates.

Best Practices

Use "ease-in-out" for elements that stay on screen to make movement feel fluid and organic. For UI elements entering the viewport, "ease-out" is best because it feels like the object is gliding to a stop. For elements exiting, "ease-in" makes them appear to accelerate away. If you are creating a mechanical effect like a ticking clock or a loading spinner that moves in chunks, use the "steps" function to avoid smooth interpolation.

Common Pitfalls

A common mistake is assuming this property applies once to the entire animation from 0% to 100%. In reality, the timing function is applied between every individual keyframe. If you have a keyframe at 50%, the curve resets and starts over for the segment between 50% and 100%. Another pitfall is trying to animate the timing function itself; it is a static definition for the animation and cannot be transitioned smoothly to a different curve.

Accessibility

Animations can trigger motion sickness or vestibular issues for some users. Always wrap your animations in a "prefers-reduced-motion" media query. Avoid jerky or overly fast custom "cubic-bezier" curves that might cause flashing or jarring movements. "linear" timing for large moving objects can feel robotic and fatiguing to track with the eyes over long periods.

Dev Data Table: animation-timing-function property

default ease
animatable no
inherited no
experimental no
year_intro 2009
year_standard 2013
js_syntax_1 object.style.animationTimingFunction = "ease-in-out";
js_syntax_2 object.style.setProperty("animation-timing-function", "cubic-bezier(0.1, 0.7, 1, 0.1)");
js_note Target the style property using camelCase or use the setProperty method for standard CSS naming.
browsers { "Chrome": 43, "Edge": 12, "Firefox": 16, "Safari": 9, "Opera": 30, "Chrome Android": 43, "Safari on iOS": 9, "Samsung Internet": 4, "Opera Mobile": 30 }
results render here...