Design.dev design.dev

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:

Hover me
transition: all 0.3s ease

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:

Box
transform
Box
opacity
Box
background
Box
box-shadow
Box
border-color
Box
multiple props

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:

Box
0.1s (100ms)
Box
0.3s (300ms)
Box
0.5s (500ms)
Box
1s (1000ms)

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:

linear
ease
ease-in
ease-out
ease-in-out
cubic-bezier

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:

Box
0s delay
Box
0.2s delay
Box
0.5s delay
Box
1s delay

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);
}
Hover over each button

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:

transform
opacity

⚠️ Paint Properties

Triggers repaint (use carefully):

color, background
box-shadow, border

❌ Layout Properties

Triggers reflow (avoid):

width, height
margin, padding
top, 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 */