What Are CSS Transitions?
CSS transitions provide a way to control animation speed when changing CSS properties. Instead of having property changes take effect immediately, transitions cause changes to occur over a specified period of time. For example, when changing an element's color from white to black, the change normally happens instantly. With CSS transitions enabled, the browser calculates and renders all intermediate color values between white and black over the duration you specify, creating a smooth visual effect (MDN Web Docs - Using CSS Transitions).
The concept behind CSS transitions relies on interpolation--the process of calculating intermediate values between a starting state and an ending state. This interpolation happens automatically in the browser's rendering engine, which means you don't need to manually specify every intermediate frame. The browser handles all the mathematics of determining what the element should look like at any point during the transition web.dev - CSS Transitions.
Visual Example: Color Interpolation
Consider a button that changes from blue (#3b82f6) to darker blue (#2563eb) on hover. Without transitions, the change happens instantly. With a 0.3-second transition, the browser calculates and renders approximately 18 frames (at 60fps), showing the color gradually darkening through hundreds of intermediate RGB values. This creates the perception of smooth motion rather than an abrupt switch.
How Transitions Differ from Animations
While CSS transitions and animations might seem similar, they serve different purposes. Transitions are reactive--they trigger when a property value changes due to user interaction or JavaScript. They have a defined start and end point and execute once per state change. Animations, on the other hand, can run automatically, repeat infinitely, and have complex multi-step keyframes. Transitions excel at simple, single-direction state changes: hover effects, focus states, modal appearances, and toggle switches. For more complex animations with multiple steps, our team can help you implement advanced web development solutions tailored to your needs.
The Four Transition Properties
The CSS transition system comprises four individual properties that control different aspects of the transition behavior. Each property can be specified individually or combined using the shorthand transition property MDN Web Docs - Using CSS Transitions.
transition-property
Specifies which CSS properties should animate. Only animatable properties like color, opacity, transform, and dimensions will produce smooth effects. Using transition-property: all will attempt to animate every property that changes, though this can sometimes produce unintended effects web.dev - CSS Transitions.
/* Animate specific properties */
.element {
transition-property: transform, opacity, background-color;
}
/* Animate all changing properties */
.element {
transition-property: all;
}
For animating element rotations and scaling, our guide on CSS rotate covers transform-specific techniques.
transition-duration
Sets how long the transition takes to complete, specified in seconds (s) or milliseconds (ms). A duration that's too short makes transitions imperceptible, while durations that are too long can feel sluggish. Most interface transitions work well between 150ms and 500ms web.dev - CSS Transitions.
/* Using seconds */
.element {
transition-duration: 0.3s;
}
/* Using milliseconds */
.element {
transition-duration: 300ms;
}
transition-timing-function
Controls the pace of the transition using easing functions like ease, linear, ease-in, ease-out, or custom cubic-bezier() values. A well-chosen easing function makes animations feel natural and purposeful Easings.net.
.element {
transition-timing-function: ease-out;
/* Or use custom bezier curves */
transition-timing-function: cubic-bezier(0.25, 1, 0.5, 1);
}
transition-delay
Specifies how long to wait before the transition begins. This is useful for creating staggered effects when multiple elements animate in sequence, or for preventing transitions from firing accidentally during rapid interactions.
.element {
transition-delay: 0.2s;
}
The Transition Shorthand Syntax
The transition property combines all four individual properties into a single declaration. The syntax follows a specific order: property duration timing-function delay. While the timing function and delay are optional and can be omitted, the duration is always required for the shorthand to work correctly MDN Web Docs - Using CSS Transitions.
/* Longhand - each property separate */
.element {
transition-property: transform;
transition-duration: 0.3s;
transition-timing-function: ease-out;
transition-delay: 0s;
}
/* Shorthand - recommended for cleaner code */
.element {
transition: transform 0.3s ease-out;
}
/* Multiple properties */
.element {
transition: transform 0.3s ease-out, opacity 0.2s ease;
}
When to Use Shorthand vs Longhand
Use shorthand when:
- Transitioning a single property or simple combination
- Writing new code for maintainability
- Performance is not a critical concern
Use longhand when:
- You need different timing functions for different properties
- Debugging transition issues in browser dev tools
- Creating complex multi-property transitions
- Gradually adding transitions to existing elements
Common Mistakes to Avoid
/* Mistake 1: Duration in wrong position */
.element {
transition: ease-out transform 0.3s; /* Wrong order */
}
/* Mistake 2: Forgetting duration is required */
.element {
transition: ease-out; /* Won't work - duration missing */
}
/* Mistake 3: Transitioning everything unnecessarily */
.element {
transition: all 0.3s; /* Can cause unexpected behavior */
}
/* Correct */
.element {
transition: transform 0.3s ease-out;
}
Which Properties Can Be Transitioned?
Understanding which CSS properties support transitions is essential for creating effective animations. The browser determines which properties are animatable based on whether they have calculable intermediate values. Color values, for instance, can be interpolated because RGB and HSL values have numeric components that can be calculated at any point between start and end MDN Web Docs - Using CSS Transitions.
Animatable Property Categories
| Category | Properties | Performance | Notes |
|---|---|---|---|
| Color | color, background-color, border-color, outline-color | Good | Hover effects are straightforward to implement |
| Layout/Sizing | width, height, max-width, min-height, flex-basis | Poor | Triggers reflow, impacts performance |
| Transform | scale, rotate, translate, skew | Excellent | GPU-composited, runs at 60fps on mobile |
| Opacity | opacity | Excellent | No repaints, GPU-accelerated |
| Typography | font-size, line-height, letter-spacing | Moderate | Can cause font re-rasterization |
| Spacing | margin, padding, gap | Poor | Triggers layout recalculation |
| Borders | border-width, border-radius | Moderate | Can trigger repaints |
| Shadows | box-shadow | Moderate | Performance varies by browser |
Performance Recommendations
For optimal performance, prioritize these animatable properties:
- Transform (
transform) - compositor-friendly, GPU-accelerated - Opacity (
opacity) - doesn't trigger repaints - Color properties - well-optimized in modern browsers
When working with flexible layouts, transitioning flex-basis or other flex properties can create smooth layout adjustments. Learn more about CSS flex for building responsive interfaces.
Non-Animatable Properties
Properties that cannot be transitioned include (MDN Web Docs - Using CSS Transitions):
| Property | Reason | Alternative |
|---|---|---|
display | No intermediate values | Use opacity with visibility |
position | Discrete values | Use transforms for movement |
float | Discrete values | Use transforms |
z-index | Discrete values | No smooth transition possible |
The Visibility Property Workaround
The visibility property can transition using opacity in combination:
.fade-element {
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0s 0.3s;
}
.fade-element.visible {
opacity: 1;
visibility: visible;
transition: opacity 0.3s ease;
}
Understanding Timing Functions
The timing function is perhaps the most impactful yet often overlooked aspect of CSS transitions. A well-chosen easing function makes animations feel natural and purposeful, while a poorly chosen one can make interfaces feel stiff or confusing (Easings.net).
Built-in Timing Keywords
CSS provides several built-in timing functions that cover common use cases (MDN Web Docs - Using CSS Transitions):
| Keyword | Curve | Feel | Best Used For |
|---|---|---|---|
ease | (0.25, 0.1, 0.25, 1) | Natural acceleration/deceleration | General UI, hover effects |
linear | (0, 0, 1, 1) | Constant velocity | Loading spinners, continuous motion |
ease-in | (0.42, 0, 1, 1) | Starts slow, accelerates | Elements leaving screen |
ease-out | (0, 0, 0.58, 1) | Starts fast, slows down | Elements entering viewport |
ease-in-out | (0.42, 0, 0.58, 1) | Slow start and end | Modal appearances |
Visual Representation of Timing Functions
Imagine a ball rolling across a surface:
- Linear: The ball moves at constant speed from start to finish
- Ease: The ball starts slowly, speeds up, then slows down before stopping
- Ease-in: The ball starts slow and accelerates continuously
- Ease-out: The ball starts fast and gradually slows to a stop
- Ease-in-out: The ball starts slow, speeds up, then slows down again
The Cubic-Bezier Function
For fine-grained control, cubic-bezier() allows you to define custom acceleration curves using four numeric values. These values represent two control points on a graph (Easings.net):
/* Ease-out equivalent */
.element {
transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1);
}
/* Custom bounce-like effect with overshoot */
.element {
transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
/* Snap-back effect */
.element {
transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
The cubic-bezier function can specify values outside the 0-1 range, creating overshoot effects where the animation goes beyond its target value before settling back (Easings.net).
Step Timing Functions
The steps() function creates transitions that jump between values rather than interpolating smoothly (MDN Web Docs - Using CSS Transitions):
/* 5 jumps, first jump happens immediately */
.element {
transition-timing-function: steps(5, start);
}
/* 5 jumps, first jump at end */
.element {
transition-timing-function: steps(5, end);
}
/* Create a progress bar effect */
.progress-step {
transition-timing-function: steps(10, end);
}
For a comprehensive reference of easing functions with visual graphs, visit Easings.net.
Transition Code Examples
Basic Hover Effect
The most common use of CSS transitions is creating smooth hover effects on interactive elements (MDN Web Docs - Using CSS Transitions). For more advanced hover interactions, explore our comprehensive guide on CSS hover effects.
.button {
background-color: #3b82f6;
color: white;
padding: 12px 24px;
border-radius: 6px;
border: none;
cursor: pointer;
transition: background-color 0.2s ease, transform 0.2s ease;
}
.button:hover {
background-color: #2563eb;
transform: scale(1.05);
}
Multiple Property Transitions
When transitioning multiple properties, you can specify each one individually (MDN Web Docs - Using CSS Transitions):
.card {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 24px;
border: 1px solid #e2e8f0;
transition: background-color 0.3s ease,
box-shadow 0.3s ease,
transform 0.3s ease,
border-color 0.3s ease;
}
.card:hover {
background-color: #f8fafc;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
border-color: #3b82f6;
transform: translateY(-4px);
}
Staggered Transitions with Delay
Using transition-delay creates visually interesting effects where multiple elements animate in sequence (web.dev - CSS Transitions):
.nav-item {
opacity: 0;
transform: translateY(10px);
transition: opacity 0.4s ease, transform 0.4s ease;
}
/* Stagger by 100ms increments */
.nav-item:nth-child(1) { transition-delay: 0ms; }
.nav-item:nth-child(2) { transition-delay: 100ms; }
.nav-item:nth-child(3) { transition-delay: 200ms; }
.nav-item:nth-child(4) { transition-delay: 300ms; }
.nav-item:nth-child(5) { transition-delay: 400ms; }
.nav:hover .nav-item {
opacity: 1;
transform: translateY(0);
}
Transform Transition with Custom Easing
Transform transitions are highly performant because they don't trigger layout reflows (web.dev - CSS Transitions):
.interactive-element {
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.interactive-element:hover {
transform: translateY(-8px) rotate(2deg) scale(1.02);
}
Focus State Transition
.input-field {
border: 2px solid #e2e8f0;
padding: 12px 16px;
border-radius: 6px;
outline: none;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.input-field:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
}
Mobile Menu Toggle
.mobile-menu {
transform: translateX(100%);
transition: transform 0.3s ease-in-out;
}
.mobile-menu.open {
transform: translateX(0);
}
.menu-toggle {
transition: transform 0.2s ease;
}
.menu-toggle.active {
transform: rotate(90deg);
}
Best Practices for Performance
GPU Compositing and Rendering Layers
Modern browsers use GPU compositing to render certain CSS properties efficiently. When you animate transform or opacity, the browser creates a separate compositing layer for that element on the GPU. This means the animation can run at a smooth 60fps without triggering expensive CPU operations (web.dev - CSS Transitions).
Reflow vs Repaint vs Composite:
| Operation | Triggered By | Performance Impact |
|---|---|---|
| Reflow | Layout changes (width, height, margin) | Expensive - recalculates element positions |
| Repaint | Visual changes (color, background, border) | Moderate - redraws pixels |
| Composite | Transform, opacity | Cheap - GPU handles layering |
Prefer Transforms and Opacity
Prioritize transforms and opacity over properties that trigger layout recalculation (reflow) or painting (repaint). For example, instead of changing width and height, use scale. Instead of changing visibility with a jarring effect, use opacity with a fade transition.
/* Good - uses transform */
.element {
transform: scale(1.1);
transition: transform 0.3s ease;
}
/* Avoid - triggers reflow */
.element {
width: 110%;
transition: width 0.3s ease;
}
Limit Transition Scope
Rather than using transition: all, explicitly list only the properties that need to animate (MDN Web Docs - Using CSS Transitions):
/* Good - specific properties only */
.element {
transition: transform 0.3s ease, opacity 0.3s ease;
}
/* Avoid - transitions everything */
.element {
transition: all 0.3s ease;
}
Match Duration to Context
Different interactions warrant different transition durations (web.dev - CSS Transitions):
| Duration | Feel | Use Cases |
|---|---|---|
| 100-150ms | Instant/snappy | Toggle switches, checkbox states |
| 150-200ms | Quick | Button hovers, small icon changes |
| 200-300ms | Natural | Most hover effects, focus states |
| 300-500ms | Smooth | Modal appearances, dropdown menus |
| 500ms+ | Deliberate | Page transitions, complex animations |
Respect Reduced Motion
Some users experience discomfort or disorientation from motion effects. The prefers-reduced-motion media query allows you to respect these preferences (web.dev - CSS Transitions):
@media (prefers-reduced-motion: reduce) {
.animated-element {
transition: none;
}
}
/* Or provide reduced-motion alternative */
@media (prefers-reduced-motion: reduce) {
.animated-element {
transition: opacity 0.1s ease;
transform: none;
}
}
Real-World Performance Tips
- Use
will-changesparingly - Only add when you know animation is coming - Avoid transitioning shadows - They can be expensive on mobile
- Batch DOM changes - Minimize reflows by grouping changes
- Use CSS containment - The
containproperty can improve rendering performance - Test on actual devices - Emulators don't show real performance characteristics
Practical applications of CSS transitions across different interface elements
Interactive Buttons and Links
Smooth color changes and subtle scale effects on hover provide immediate visual feedback. This is the most common use of CSS transitions.
Navigation and Menus
Dropdown appearances, active state indicators, and mobile menu toggles with staggered animations add polish to navigation.
Cards and Content Blocks
Subtle elevation changes, border color shifts, and background adjustments make cards feel tactile and responsive on hover.
Form Elements
Focus, error states, and validation feedback with smooth transitions on input fields improve accessibility and user experience.
Modals and Overlays
Fade-in and scale effects create depth and focus attention on modal content while maintaining visual continuity.
Image Galleries
Smooth transitions between images, caption reveals, and thumbnail hover effects enhance gallery interactivity.
Advanced Techniques
Transitioning Height from Auto
Transitioning to or from height: auto is not directly supported in CSS. However, you can achieve this effect using max-height with a value larger than the content will ever be (MDN Web Docs - Using CSS Transitions):
.collapsible {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.collapsible.open {
max-height: 500px; /* Larger than content will ever be */
}
For more precise control, consider using JavaScript to calculate the exact height:
element.style.transition = 'height 0.3s ease';
element.style.height = 'auto';
const height = element.offsetHeight;
element.style.height = '0px';
requestAnimationFrame(() => {
element.style.height = height + 'px';
});
JavaScript Integration
While CSS transitions handle the interpolation automatically, JavaScript can be used to listen for transition events (MDN Web Docs - Using CSS Transitions):
element.addEventListener('transitionend', (e) => {
console.log('Transition completed on', e.propertyName);
// Trigger follow-up animations or clean up resources
});
// Listen for specific property
element.addEventListener('transitionend', (e) => {
if (e.propertyName === 'transform') {
// Handle transform completion
}
});
Combining with CSS Variables
Create dynamic transitions based on CSS custom properties:
:root {
--transition-duration: 0.3s;
--transition-easing: ease-out;
}
.element {
transition: transform var(--transition-duration) var(--transition-easing);
}
/* Theme-based transitions */
[data-theme="dark"] {
--transition-duration: 0.5s;
}
CSS Grid Animation Tips
Grid properties like grid-template-columns cannot be transitioned directly. However, you can animate the contents or use transforms on grid items:
.grid-item {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.grid-container:hover .grid-item {
transform: scale(0.95);
}
Responsive Transition Considerations
Adjust transitions based on device capabilities:
.element {
transition: transform 0.3s ease;
}
@media (hover: none) and (pointer: coarse) {
.element {
/* Touch devices might need faster transitions */
transition: transform 0.15s ease;
}
}
Reversing Transitions
By default, transitions apply in both directions--when the trigger is added and when it's removed (web.dev - CSS Transitions). You can modify this behavior:
.element {
/* Fast out, slow back */
transition: transform 0.2s ease-out 0s, transform 0.5s ease-in 0s;
}
/* Or use different properties */
.element {
transition: transform 0.3s ease;
}
.element.leaving {
/* Different easing for exit */
transition: transform 0.5s ease;
}