CSS Transitions
Smooth state changes without JavaScript or keyframes
Transition Syntax
A transition smoothly animates a CSS property from one value to another. You define the transition on the element’s default state, and it activates whenever that property changes (e.g., on hover).
.button {
background: #6366f1;
transition: background 0.2s ease;
}
.button:hover {
background: #4f46e5;
}
/* Longhand */
.element {
transition-property: opacity, transform;
transition-duration: 0.3s;
transition-timing-function: ease-out;
transition-delay: 0s;
}
/* Shorthand: property duration timing-function delay */
.element {
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
}
Live Examples
Hover over these buttons to see different transitions in action:
Timing Functions
The timing function controls the acceleration curve. Here are the built-in options:
- ease — starts slow, speeds up, ends slow (default)
- ease-in — starts slow, accelerates
- ease-out — starts fast, decelerates (best for enter animations)
- ease-in-out — slow at both ends
- linear — constant speed
- cubic-bezier(x1, y1, x2, y2) — custom curve
/* Material Design standard easing */
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
/* Bounce effect */
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55);
/* Snappy UI response */
transition: opacity 0.15s ease-out;
What to Transition (and What Not To)
Fast (GPU-accelerated)
opacitytransform(translate, scale, rotate)
Acceptable
background-color,color,border-colorbox-shadow
Avoid transitioning
width,height— trigger layout recalculationstop,left— usetransform: translate()insteadall— watches every property, prevents optimizations
/* BAD: triggers layout on every frame */
.card { transition: width 0.3s; }
.card:hover { width: 350px; }
/* GOOD: GPU-accelerated, no layout recalc */
.card { transition: transform 0.3s; }
.card:hover { transform: scale(1.05); }
Common Patterns
Fade In/Out
.element {
opacity: 0;
transition: opacity 0.3s ease-out;
}
.element.visible {
opacity: 1;
}
Slide Down
.dropdown {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.dropdown.open {
max-height: 500px; /* larger than content */
}
Card Hover Effect
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}
Respect User Preferences
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0.01ms !important;
}
}
Transition Delay
Add a delay before the transition starts. Useful for staggered animations on lists:
.item:nth-child(1) { transition-delay: 0ms; }
.item:nth-child(2) { transition-delay: 50ms; }
.item:nth-child(3) { transition-delay: 100ms; }
.item:nth-child(4) { transition-delay: 150ms; }
Frequently Asked Questions
What CSS properties can be transitioned?
Properties with numeric or color values: opacity, transform, colors, dimensions, shadows, etc.
display and font-family cannot be transitioned. For performance, prefer opacity and transform — they are GPU-accelerated.What is the difference between transitions and animations?
Transitions need a trigger (hover, class toggle) and go from A to B. Animations (
@keyframes) run automatically, can loop, and support multiple steps. Use transitions for state changes. Use animations for looping effects or multi-step sequences.Why is transition: all bad for performance?
transition: all makes the browser watch every property. If a layout property changes, it recalculates layout every frame. Specifying exact properties (transition: opacity 0.2s, transform 0.2s) lets the browser optimize and avoids accidental animations.