🌞

CSS Transitions

Smooth state changes that make your UI feel alive. Master the art of animating between CSS property values with timing, easing, and performance in mind.

Transition Basics

Transitions let you smoothly animate changes between CSS property values. Instead of an instant jump from one state to another, transitions create a smooth visual flow that feels natural and polished.

Hover me!
CSS
.box {
    background-color: #2563eb;
    transform: scale(1);
    /* property | duration | timing-function | delay */
    transition: all 0.3s ease 0s;
}

.box:hover {
    background-color: #7c3aed;
    transform: scale(1.1);
}

The transition property is shorthand for four individual properties:

  • transition-property: Which CSS properties to animate (or all)
  • transition-duration: How long the transition takes (e.g., 0.3s)
  • transition-timing-function: The easing curve (e.g., ease, linear)
  • transition-delay: Wait time before starting (default: 0s)

Timing Functions

Timing functions control the acceleration curve of your transition. They determine whether the animation starts slow and speeds up, or starts fast and slows down. Choose the right easing for the right context.

linear
ease
ease-in
ease-out
ease-in-out
CSS
/* Built-in timing functions */
.linear      { transition-timing-function: linear; }
.ease        { transition-timing-function: ease; }      /* default */
.ease-in     { transition-timing-function: ease-in; }   /* slow start */
.ease-out    { transition-timing-function: ease-out; }  /* slow end */
.ease-in-out { transition-timing-function: ease-in-out; }

/* Custom cubic-bezier curves */
.custom {
    transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
    /* bounce effect */
}

Choosing the Right Timing Function

  • linear: Constant speed - good for continuous motion like loading spinners
  • ease: Starts fast, ends slow - the default, works for most cases
  • ease-in: Starts slow, accelerates - good for objects exiting the screen
  • ease-out: Starts fast, decelerates - good for objects entering the screen
  • ease-in-out: Slow start and end - good for attention-grabbing effects

For custom curves, use cubic-bezier.com to visualize and create your own timing functions.

Transitioning Multiple Properties

You can transition multiple properties at once, each with its own duration and timing. This creates rich, layered effects that feel premium and well-crafted.

🎨

Hover Me

Multiple properties transition together

CSS
.card {
    background: white;
    transform: translateY(0) scale(1);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    opacity: 0.9;
    /* Different durations for each property */
    transition:
        transform 0.3s ease-out,
        box-shadow 0.3s ease-out,
        background 0.5s ease,
        opacity 0.2s ease;
}

.card:hover {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    transform: translateY(-8px) scale(1.02);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
    opacity: 1;
}

Pro tip: While transition: all is convenient during prototyping, it's better to specify individual properties in production. This gives you fine control over timing and avoids unintended transitions on properties you didn't mean to animate.

Real-World Examples

Transitions shine in everyday UI patterns. Here are some practical applications you'll use constantly.

Button Hover States

CSS
.button {
    padding: 12px 24px;
    border: 2px solid #2563eb;
    background: #2563eb;
    color: white;
    transition: all 0.2s ease;
}

.button:hover {
    background: #1d4ed8;
    border-color: #1d4ed8;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}

.button:active {
    transform: translateY(0);
    box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2);
}

Navigation Menus

CSS
.nav-link {
    position: relative;
    color: #64748b;
    transition: color 0.2s ease;
}

.nav-link::after {
    content: '';
    position: absolute;
    bottom: -4px;
    left: 0;
    width: 0;
    height: 2px;
    background: #2563eb;
    transition: width 0.3s ease;
}

.nav-link:hover {
    color: #2563eb;
}

.nav-link:hover::after {
    width: 100%;
}

Image Hover Effects

🖼️

View Details

CSS
.image-card {
    position: relative;
    overflow: hidden;
}

.image-card img {
    transition: transform 0.4s ease;
}

.image-overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.7);
    opacity: 0;
    transition: opacity 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-card:hover img {
    transform: scale(1.1);
}

.image-card:hover .image-overlay {
    opacity: 1;
}

Performance & Best Practices

Not all CSS properties are created equal when it comes to animation performance. Some trigger expensive layout recalculations, while others can be GPU-accelerated for buttery smooth transitions.

Properties to Prefer (GPU-accelerated)

  • transform - translate, scale, rotate, skew
  • opacity - fade in/out effects

Properties to Avoid Animating (Expensive)

  • width / height - triggers layout recalculation
  • top / left - use transform: translate() instead
  • margin / padding - affects layout

Accessibility Considerations

Some users prefer reduced motion. Respect their preferences with a media query:

CSS
/* Default transitions */
.element {
    transition: transform 0.3s ease;
}

/* Disable for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
    .element {
        transition: none;
    }
}

When to Use Transitions vs Animations

Use Transitions when: You're animating between two states (like hover effects, toggles, or UI feedback).

Use Animations when: You need complex, multi-step sequences, looping effects, or animations that start automatically. Check out the Animations page for more on keyframe animations.

Transition Delays & Staggering

The transition-delay property lets you wait before starting a transition. This is perfect for creating staggered animations where elements appear one after another.

1
2
3
4
5

Hover over the container to see staggered transitions

CSS
.stagger-box {
    opacity: 0.3;
    transform: translateY(20px);
    transition: all 0.4s ease;
}

/* Stagger delays for each box */
.stagger-box:nth-child(1) { transition-delay: 0s; }
.stagger-box:nth-child(2) { transition-delay: 0.1s; }
.stagger-box:nth-child(3) { transition-delay: 0.2s; }
.stagger-box:nth-child(4) { transition-delay: 0.3s; }
.stagger-box:nth-child(5) { transition-delay: 0.4s; }

.stagger-container:hover .stagger-box {
    opacity: 1;
    transform: translateY(0);
}