Timing functions control how an animation progresses over time. They define the acceleration curve, determining whether an animation starts fast and slows down, or starts slow and speeds up.
Understanding timing functions
A timing function (also called an easing function) maps the progress of an animation from start to finish. The same animation with different timing functions will feel completely different.
Available timing functions
Linear
The animation proceeds at a constant rate from start to finish.
.element {
transition: transform 1s linear;
}
Visual effect: Mechanical and uniform. The element moves at exactly the same speed throughout the entire animation.
When to use:
- Loading spinners and progress bars
- Continuous rotations
- Mechanical or robotic movements
Ease (default)
Starts slowly, speeds up in the middle, then slows down at the end.
.element {
transition: transform 1s ease;
}
Visual effect: Natural and smooth. This is the default timing function and works well for most animations.
When to use:
- General-purpose animations
- UI transitions
- When unsure which timing to use
Ease-in
Starts slowly and gradually accelerates toward the end.
.element {
transition: transform 1s ease-in;
}
Visual effect: The animation begins tentatively and builds momentum, like an object starting to roll downhill.
When to use:
- Elements exiting the screen
- Objects falling or accelerating
- Creating anticipation before a fast action
Ease-out
Starts quickly and decelerates toward the end.
.element {
transition: transform 1s ease-out;
}
Visual effect: The animation starts with energy and gently settles into place, like an object coming to rest.
When to use:
- Elements entering the screen
- Buttons responding to clicks
- Modals and dialogs appearing
- Most interactive UI feedback
Ease-in-out
Starts slowly, speeds up in the middle, then slows down again.
.element {
transition: transform 1s ease-in-out;
}
Visual effect: Symmetrical acceleration and deceleration, creating a polished, elegant feel.
When to use:
- Smooth transitions between states
- Page transitions
- Carousel animations
- Hover effects that reverse
React implementation example
Here’s how the Animation Playground demonstrates timing functions:
import { motion } from 'framer-motion'
import { useState } from 'react'
type TimingFunction = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut'
export default function TimingDemo() {
const [selectedTiming, setSelectedTiming] = useState<TimingFunction>('linear')
const [isAnimating, setIsAnimating] = useState(false)
const handleAnimate = () => {
setIsAnimating(true)
setTimeout(() => setIsAnimating(false), 1500)
}
return (
<div>
<motion.div
animate={{ x: isAnimating ? 'calc(100% - 128px)' : 0 }}
transition={{
duration: 1.5,
ease: selectedTiming.toLowerCase()
}}
className="w-32 h-32 bg-blue-500"
>
Timing Box
</motion.div>
<button onClick={handleAnimate}>
{isAnimating ? 'Animating...' : 'Start Animation'}
</button>
</div>
)
}
Custom cubic bezier curves
For precise control, you can define custom timing functions using cubic-bezier:
.element {
transition: transform 1s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
This creates a custom curve with four control points. Tools like cubic-bezier.com help visualize these curves.
Common custom curves
transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
Creates a bouncy, overshooting effect.transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
Quick, snappy animations (Material Design standard).transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
Very smooth, flowing motion.
Choosing the right timing function
The timing function you choose dramatically affects how your animation feels. Experiment with different options to find what works best.
Decision guide
For entering elements: Use ease-out
- Makes elements feel responsive and energetic
- Creates the impression of elements “arriving” at their destination
For exiting elements: Use ease-in
- Elements smoothly accelerate as they leave
- Feels natural for dismissing UI
For state changes: Use ease or ease-in-out
- Balanced acceleration works well for toggles
- Symmetrical motion feels polished
For continuous animations: Use linear
- Progress bars need constant speed
- Rotations look better without acceleration
Timing with Framer Motion
Framer Motion provides additional easing options:
<motion.div
animate={{ x: 100 }}
transition={{
type: "spring",
stiffness: 100,
damping: 10
}}
/>
Tween (default)
Spring
Inertia
transition={{
type: "tween",
ease: "easeOut",
duration: 0.3
}}
Traditional CSS-style easing.transition={{
type: "spring",
stiffness: 100,
damping: 10
}}
Physics-based spring animations.transition={{
type: "inertia",
velocity: 50
}}
Realistic deceleration based on velocity.
Timing functions themselves don’t impact performance, but longer durations mean longer repaints. Keep animations under 500ms for UI interactions.
Duration guidelines
- Micro-interactions: 100-200ms
- UI transitions: 200-400ms
- Page transitions: 400-600ms
- Decorative animations: 600-1000ms
Pair faster timing functions (like ease-out) with shorter durations for responsive UIs.