/
CSS transitions let you smoothly animate changes between two states of an element. Instead of a property snapping instantly from one value to another, a transition creates a gradual change over a specified duration.
Without a transition, hovering over a button changes its color instantly. With a transition, the color fades smoothly.
The `transition` shorthand combines four individual properties: property, duration, timing function, and delay.
/* Shorthand: property duration timing-function delay */
.button {
background-color: #3498db;
color: white;
padding: 12px 24px;
border: none;
border-radius: 6px;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #2980b9;
}The `transition-property` specifies which CSS property to animate.
/* Single property */
.box {
transition-property: background-color;
}
/* Multiple properties */
.card {
transition-property: transform, box-shadow, background-color;
}
/* All animatable properties */
.element {
transition-property: all;
}Performance tip: Avoid using `all` in production. Instead, list the specific properties you want to animate. Transitioning `all` can cause unexpected animations and performance issues.
/* Bad: transitions everything, including layout properties */
.card {
transition: all 0.3s ease;
}
/* Good: only transition what you need */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}The `transition-duration` sets how long the transition takes.
.fast { transition-duration: 0.15s; } /* Quick micro-interaction */
.normal { transition-duration: 0.3s; } /* Standard UI transition */
.slow { transition-duration: 0.5s; } /* Deliberate, noticeable */
.very-slow { transition-duration: 1s; } /* Dramatic effect */Guidelines for duration:
The `transition-timing-function` controls the speed curve of the transition. This determines how the animation accelerates and decelerates.
.ease { transition-timing-function: ease; }
/* Default. Slow start, fast middle, slow end */
.linear { transition-timing-function: linear; }
/* Constant speed throughout */
.ease-in { transition-timing-function: ease-in; }
/* Starts slow, ends fast */
.ease-out { transition-timing-function: ease-out; }
/* Starts fast, ends slow - feels most natural for UI */
.ease-in-out { transition-timing-function: ease-in-out; }
/* Slow start and end, fast middle */For precise control, use `cubic-bezier()` to define your own timing curve.
/* Snappy feel */
.snappy {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
/* Bouncy overshoot */
.bouncy {
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
/* Quick start, gentle end */
.quick-out {
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}Best practice: Use `ease-out` for elements entering the screen, `ease-in` for elements leaving, and `ease-in-out` for elements changing state in place.
The `transition-delay` sets a waiting period before the transition starts.
.delayed {
transition: transform 0.3s ease 0.1s; /* 0.1s delay */
}
/* Staggered effect on multiple items */
.item:nth-child(1) { transition-delay: 0s; }
.item:nth-child(2) { transition-delay: 0.05s; }
.item:nth-child(3) { transition-delay: 0.1s; }
.item:nth-child(4) { transition-delay: 0.15s; }/* Same duration and timing for all */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
/* Different durations */
.element {
transition: background-color 0.2s ease, transform 0.4s ease-out, opacity 0.3s ease;
}
/* Shorthand with multiple */
.button {
background-color: #3498db;
color: white;
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition:
background-color 0.2s ease,
transform 0.3s ease,
box-shadow 0.3s ease;
}
.button:hover {
background-color: #2980b9;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}.card {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12);
}.link {
position: relative;
text-decoration: none;
color: #333;
}
.link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 100%;
height: 2px;
background-color: #3498db;
transform: scaleX(0);
transform-origin: right;
transition: transform 0.3s ease;
}
.link:hover::after {
transform: scaleX(1);
transform-origin: left;
}.btn-gradient {
padding: 12px 32px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
background-size: 200% 200%;
background-position: 0% 50%;
transition: background-position 0.5s ease;
}
.btn-gradient:hover {
background-position: 100% 50%;
}.search-input {
width: 200px;
padding: 10px 16px;
border: 2px solid #ddd;
border-radius: 50px;
outline: none;
transition: width 0.4s ease, border-color 0.3s ease;
}
.search-input:focus {
width: 350px;
border-color: #3498db;
}.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease;
}
.accordion.open .accordion-content {
max-height: 500px;
}.fade-element {
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.fade-element.visible {
opacity: 1;
visibility: visible;
}.image-card {
position: relative;
overflow: hidden;
border-radius: 12px;
}
.image-card img {
width: 100%;
display: block;
transition: transform 0.5s ease;
}
.image-card .overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.image-card:hover img {
transform: scale(1.1);
}
.image-card:hover .overlay {
opacity: 1;
}Not all CSS properties can be transitioned. Properties that can be transitioned have a clear start and end value that can be interpolated. Here are the most commonly transitioned properties:
Properties that cannot be transitioned include `display`, `font-family`, and `position`.
Some users experience discomfort or nausea from animations. Always respect the `prefers-reduced-motion` media query.
/* Disable transitions for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
transition-duration: 0.01ms;
transition-delay: 0ms;
}
}This is essential for accessibility and should be included in every project.
CSS transitions bring your interfaces to life with smooth, polished state changes. Set the property to animate, the duration for speed, a timing function for feel, and an optional delay. Use `ease-out` for natural-feeling UI interactions, keep durations under 0.5s for responsiveness, and always include a `prefers-reduced-motion` fallback for accessibility. For best performance, transition only `transform` and `opacity` whenever possible.
In the next article, you will learn about CSS keyframe animations for more complex motion.