CSS Transitions Guide
A complete reference for CSS transitions. Create smooth, animated changes between CSS property values. Perfect for hover effects, state changes, and micro-interactions.
Transition Basics
Transitions smoothly animate changes in CSS property values over a specified duration.
How Transitions Work
/* 1. Define the transition on the base state */
.element {
background: blue;
transition: background 0.3s ease;
}
/* 2. Change the property value on state change */
.element:hover {
background: purple; /* Animates from blue to purple */
}
/* Transitions require:
- A property that CAN be animated
- A trigger that changes the property value
- transition defined BEFORE the change occurs */
Transition Shorthand
/* transition: property duration timing-function delay */
.element {
transition: all 0.3s ease 0s; /* Full syntax */
transition: opacity 0.3s ease; /* Common usage */
transition: transform 0.5s; /* Minimal (ease default) */
transition: all 0.3s; /* All properties */
}
Hover over the box to see a basic transition:
transition-property
Specify which CSS properties should be animated.
Syntax & Values
/* Specific property */
.element {
transition-property: opacity;
transition-property: transform;
transition-property: background-color;
}
/* Multiple properties */
.element {
transition-property: opacity, transform;
transition-property: color, background-color, border-color;
}
/* All animatable properties */
.element {
transition-property: all;
}
/* No transition */
.element {
transition-property: none;
}
Animatable Properties
| Category | Properties |
|---|---|
| Transform | transform |
| Opacity | opacity |
| Colors | color, background-color, border-color, outline-color |
| Dimensions | width, height, max-width, max-height |
| Spacing | margin, padding, gap |
| Position | top, right, bottom, left |
| Box Model | box-shadow, border-radius, border-width |
| Text | font-size, letter-spacing, line-height, text-indent |
| Background | background, background-position, background-size |
| Filter | filter, backdrop-filter |
Hover to see different properties animated:
transition-duration
How long the transition takes to complete.
Syntax & Values
/* Seconds */
.element {
transition-duration: 0.3s; /* 300ms - snappy */
transition-duration: 0.5s; /* 500ms - smooth */
transition-duration: 1s; /* 1000ms - slow */
}
/* Milliseconds */
.element {
transition-duration: 150ms; /* Quick micro-interaction */
transition-duration: 300ms; /* Standard hover */
transition-duration: 500ms; /* Emphasis effect */
}
/* Multiple durations (for multiple properties) */
.element {
transition-property: opacity, transform;
transition-duration: 0.3s, 0.5s; /* opacity: 0.3s, transform: 0.5s */
}
Recommended Durations
⚡ 100-200ms
Micro-interactions: button clicks, checkbox toggles, small state changes. Feels instant but smooth.
🎯 200-400ms
Standard UI: hover effects, menu reveals, card interactions. The sweet spot for most transitions.
🌊 400-600ms
Emphasis: modal appearances, page transitions, attention-grabbing effects. Noticeable but not slow.
Compare different durations:
Timing Functions
Control the acceleration curve of the transition.
Built-in Timing Functions
/* Keyword values */
.element {
/* Constant speed throughout */
transition-timing-function: linear;
/* Slow start, fast middle, slow end (default) */
transition-timing-function: ease;
/* Slow start, fast end */
transition-timing-function: ease-in;
/* Fast start, slow end */
transition-timing-function: ease-out;
/* Slow start and end */
transition-timing-function: ease-in-out;
}
Interactive Comparison
Hover over the container to see all timing functions race:
Custom Cubic Bezier
/* cubic-bezier(x1, y1, x2, y2) */
.element {
/* Standard ease equivalent */
transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
/* Material Design standard */
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
/* Bouncy overshoot */
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
/* Snappy */
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
/* Smooth deceleration */
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
/* Common presets */
:root {
--ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
--ease-in-out-circ: cubic-bezier(0.85, 0, 0.15, 1);
}
Steps Function
/* Stepped transitions (no smoothing) */
.element {
/* 5 discrete steps */
transition-timing-function: steps(5);
transition-timing-function: steps(5, end); /* Jump at end of step */
transition-timing-function: steps(5, start); /* Jump at start of step */
/* Jump keywords */
transition-timing-function: steps(4, jump-start);
transition-timing-function: steps(4, jump-end);
transition-timing-function: steps(4, jump-none);
transition-timing-function: steps(4, jump-both);
/* Single step */
transition-timing-function: step-start; /* steps(1, start) */
transition-timing-function: step-end; /* steps(1, end) */
}
Tip: Use Cubic Bezier Studio to create and preview custom timing functions visually.
transition-delay
Wait before starting the transition.
Syntax & Values
/* Positive delay - waits before starting */
.element {
transition-delay: 0s; /* No delay (default) */
transition-delay: 0.2s; /* 200ms delay */
transition-delay: 500ms; /* Half second delay */
}
/* Negative delay - starts partway through */
.element {
transition-duration: 1s;
transition-delay: -0.5s; /* Starts at 50% progress */
}
/* Multiple delays */
.element {
transition-property: opacity, transform;
transition-duration: 0.3s, 0.3s;
transition-delay: 0s, 0.1s; /* transform starts 100ms after opacity */
}
Compare different delays:
Staggered Delays
/* Create staggered animation effect */
.item:nth-child(1) { transition-delay: 0s; }
.item:nth-child(2) { transition-delay: 0.1s; }
.item:nth-child(3) { transition-delay: 0.2s; }
.item:nth-child(4) { transition-delay: 0.3s; }
/* Using CSS custom properties */
.item {
transition: opacity 0.3s ease;
transition-delay: calc(var(--index) * 0.1s);
}
/* Set via inline style or JS */
/* <div style="--index: 0"> */
/* <div style="--index: 1"> */
Shorthand Syntax
Combine all transition properties in one declaration.
Shorthand Order
/* transition: property duration timing-function delay */
.element {
/* Full syntax */
transition: opacity 0.3s ease-out 0.1s;
/* Without delay (0s default) */
transition: opacity 0.3s ease-out;
/* Without timing (ease default) */
transition: opacity 0.3s;
/* All properties */
transition: all 0.3s ease;
}
/* ⚠️ Time values order matters! */
/* First time value = duration, second = delay */
.element {
transition: opacity 0.3s 0.1s;
/* duration: 0.3s, delay: 0.1s */
}
Common Patterns
/* Quick hover feedback */
.button {
transition: all 0.15s ease;
}
/* Smooth color change */
.link {
transition: color 0.2s ease-out;
}
/* Card lift effect */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
/* Modal appearance */
.modal {
transition: opacity 0.3s ease, transform 0.3s ease;
}
/* Drawer slide */
.drawer {
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
Multiple Transitions
Animate different properties with different settings.
Comma-Separated List
/* Different duration for each property */
.element {
transition:
opacity 0.2s ease,
transform 0.3s ease-out,
background-color 0.5s ease;
}
/* Different timing and delays */
.element {
transition:
opacity 0.3s ease 0s,
transform 0.3s ease-out 0.1s,
box-shadow 0.3s ease 0.2s;
}
/* Complex hover effect */
.card {
transition:
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
background 0.5s ease;
}
.card:hover {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
background: #f8f9fa;
}
Longhand Properties
/* Individual properties with lists */
.element {
transition-property: opacity, transform, background;
transition-duration: 0.2s, 0.3s, 0.5s;
transition-timing-function: ease, ease-out, ease;
transition-delay: 0s, 0.1s, 0s;
}
/* If fewer values than properties, they cycle */
.element {
transition-property: opacity, transform, background;
transition-duration: 0.3s; /* All use 0.3s */
transition-timing-function: ease, ease-out; /* background uses ease */
}
Performance Note: Avoid using transition: all when you only need specific properties. It can cause unexpected transitions and performance issues.
Common Patterns
Ready-to-use transition patterns for typical UI elements.
Button Hover Effects
/* Lift effect */
.btn-lift {
transition: transform 0.2s ease;
}
.btn-lift:hover {
transform: translateY(-3px);
}
/* Grow with shadow */
.btn-grow {
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
transition: transform 0.2s ease, box-shadow 0.3s ease;
}
.btn-grow:hover {
transform: scale(1.05);
box-shadow: 0 8px 25px rgba(0,0,0,0.3);
}
/* Press feedback */
.btn-press {
transition: transform 0.1s ease;
}
.btn-press:active {
transform: scale(0.98);
}
/* Glow effect */
.btn-glow {
transition: box-shadow 0.3s ease;
}
.btn-glow:hover {
box-shadow: 0 0 30px rgba(102, 126, 234, 0.6);
}
Card Hover
.card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0,0,0,0.15);
}
Interactive Card
Hover to see the lift effect with smooth shadow and border transitions.
Menu Item Slide
.menu-item {
padding-left: 1rem;
transition:
background 0.2s ease,
color 0.2s ease,
padding-left 0.2s ease;
}
.menu-item:hover {
background: rgba(102, 126, 234, 0.1);
color: #667eea;
padding-left: 1.5rem;
}
Image Zoom in Container
.image-container {
overflow: hidden;
border-radius: 8px;
}
.image-container img {
transition: transform 0.5s ease;
}
.image-container:hover img {
transform: scale(1.1);
}
Link Underline Animation
.link {
position: relative;
text-decoration: none;
}
.link::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: currentColor;
transition: width 0.3s ease;
}
.link:hover::after {
width: 100%;
}
Accessibility
Respect user preferences for reduced motion.
prefers-reduced-motion
/* Remove transitions for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}
/* Alternative: Keep very short transitions */
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0.1s !important;
}
}
/* Targeted approach */
@media (prefers-reduced-motion: reduce) {
.animated-element {
transition: none;
}
}
/* Only add transitions when motion is OK */
@media (prefers-reduced-motion: no-preference) {
.element {
transition: transform 0.3s ease;
}
}
Best Practices
/* Use opacity instead of movement for subtle feedback */
.button {
transition: opacity 0.2s ease;
}
.button:hover {
opacity: 0.8;
}
/* Keep essential state changes visible */
.toggle {
/* Position change still works, just instant */
transition: background-color 0.2s ease;
}
/* Avoid: Large movements that can cause vestibular issues */
.avoid {
transition: transform 1s ease;
}
.avoid:hover {
transform: translateX(200px) rotate(360deg); /* Can cause discomfort */
}
Important: About 1 in 3 people experience motion sensitivity. Always provide reduced motion alternatives for significant animations.
Performance Tips
Keep transitions smooth and efficient.
Best Properties to Transition
✅ Compositor Properties
GPU-accelerated, smooth 60fps:
transformopacity
⚠️ Paint Properties
Triggers repaint (use carefully):
color, backgroundbox-shadow, border
❌ Layout Properties
Triggers reflow (avoid):
width, heightmargin, paddingtop, left
Optimization Techniques
/* ❌ Bad - animates layout */
.element {
left: 0;
transition: left 0.3s;
}
.element:hover {
left: 100px;
}
/* ✅ Good - uses transform */
.element {
transform: translateX(0);
transition: transform 0.3s;
}
.element:hover {
transform: translateX(100px);
}
/* ❌ Bad - animates width */
.element {
width: 100px;
transition: width 0.3s;
}
/* ✅ Good - uses scale */
.element {
transform: scaleX(1);
transition: transform 0.3s;
}
.element:hover {
transform: scaleX(2);
}
/* Use will-change sparingly */
.element {
will-change: transform; /* Hint browser */
}
/* Avoid: */
* { will-change: transform; } /* Too broad */
Avoid Transition: all
/* ❌ Avoid - transitions everything */
.element {
transition: all 0.3s ease;
}
/* ✅ Better - specific properties */
.element {
transition:
transform 0.3s ease,
opacity 0.3s ease;
}
/* Why? "all" can cause:
- Unexpected transitions
- Performance issues
- Jank when properties change unexpectedly */
Debugging Tips
/* Chrome DevTools: Slow down animations */
/* Rendering tab → Check "Force CSS animations/transitions to be slow" */
/* Detect layout thrashing in Performance tab */
/* Look for purple "Layout" bars during animations */
/* Test with CPU throttling enabled */
/* Performance tab → CPU: 4x slowdown */