CSS transitions let you smoothly change property values over a set duration — no JavaScript required. Instead of a style jumping instantly from one value to another, a transition gives it a smooth, controlled animation. In this guide, you'll learn how transitions work, which properties you can animate, and how to use timing functions to control the feel of your animations.

What is a CSS transition?

A CSS transition is a way to animate the change between two states of an element. When a property value changes — for example, on hover — instead of switching immediately, the browser interpolates between the old and new value over a set time.

Transitions are defined on the element that will change, not on the state that triggers the change. You tell the browser: "when any property on this element changes, animate it over X seconds."

/* Basic syntax */
.element {
  transition: property duration timing-function delay;
}

/* Example */
.button {
  background-color: #3b82f6;
  transition: background-color 0.3s ease;
}

.button:hover {
  background-color: #1d4ed8;
}

In the example above, when the button is hovered, the background colour smoothly changes from blue to a darker blue over 0.3 seconds instead of switching instantly.

The Four CSS Transition Properties

The transition shorthand combines four individual properties. Understanding each one gives you precise control over your animations.

1. transition-property

Specifies which CSS property to animate. You can target a single property, a comma-separated list, or use all to animate every changing property.

/* Animate only opacity */
transition-property: opacity;

/* Animate opacity and transform */
transition-property: opacity, transform;

/* Animate everything (use carefully) */
transition-property: all;

Avoid using all on performance-critical elements — it forces the browser to watch every property and can cause jank on lower-end devices.

2. transition-duration

Sets how long the transition takes, in seconds (s) or milliseconds (ms). There is no default — you must always define a duration, otherwise the transition won't run.

transition-duration: 0.3s;   /* 300 milliseconds */
transition-duration: 500ms;  /* same as 0.5s */

3. transition-timing-function

Controls the speed curve of the animation — how fast or slow it moves at different points during the transition. This is what makes an animation feel mechanical or natural.

transition-timing-function: ease;         /* slow start, fast middle, slow end */
transition-timing-function: linear;       /* constant speed */
transition-timing-function: ease-in;      /* slow start, fast end */
transition-timing-function: ease-out;     /* fast start, slow end */
transition-timing-function: ease-in-out;  /* slow start and end */
transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); /* custom curve */

For most UI interactions, ease or ease-out feel the most natural. linear tends to feel robotic unless you're animating something like a loading bar.

4. transition-delay

Sets how long the browser waits before starting the transition. Useful when you want to stagger multiple animations or delay a tooltip from appearing instantly.

transition-delay: 0s;    /* no delay (default) */
transition-delay: 0.2s;  /* wait 200ms before starting */

The Shorthand Syntax

You'll most often use the shorthand transition property to keep things clean. The order is: property → duration → timing-function → delay.

/* Single property */
.card {
  transition: transform 0.3s ease-out;
}

/* Multiple properties */
.card {
  transition:
    transform 0.3s ease-out,
    box-shadow 0.3s ease,
    opacity 0.2s linear;
}

/* Animate all with delay */
.card {
  transition: all 0.4s ease 0.1s;
}

When transitioning multiple properties, list each one separately with a comma. This gives you independent control over the duration and timing of each property.

Which CSS Properties Can Be Transitioned?

Not every CSS property is animatable. A property can be transitioned only if the browser can calculate intermediate values between its start and end states. The most commonly transitioned properties include:

  • Visual: opacity, color, background-color, border-color, box-shadow
  • Size and spacing: width, height, padding, margin, border-width
  • Transform: transform (translate, scale, rotate)
  • Position: top, left, right, bottom
  • Typography: font-size, letter-spacing, line-height

Properties like display, visibility, and z-index cannot be smoothly transitioned. display: none to display: block is a binary switch — there's no in-between value for the browser to animate.

Performance Tip: Stick to opacity and transform

For the smoothest animations, limit transitions to opacity and transform whenever possible. These two properties are handled by the GPU and do not trigger layout recalculations. Animating width, height, margin, or top/left forces the browser to recalculate the layout on every frame, which can cause dropped frames on slow devices.

/* Smooth (GPU-accelerated) */
.element {
  transition: opacity 0.3s ease, transform 0.3s ease;
}

/* Avoid for smooth performance */
.element {
  transition: width 0.3s ease, margin 0.3s ease;
}

Practical Examples

Hover Button Effect

.btn {
  background-color: #3b82f6;
  color: #fff;
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition: background-color 0.2s ease, transform 0.2s ease;
}

.btn:hover {
  background-color: #1d4ed8;
  transform: translateY(-2px);
}

Fade In on Hover

.overlay {
  opacity: 0;
  transition: opacity 0.3s ease;
}

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

Smooth Navigation Link Underline

.nav-link {
  text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: border-color 0.2s ease;
}

.nav-link:hover {
  border-color: #3b82f6;
}

Card Lift on Hover

.card {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: box-shadow 0.3s ease, transform 0.3s ease;
}

.card:hover {
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  transform: translateY(-4px);
}

CSS Transitions vs CSS Animations

Both transitions and animations move elements from one state to another, but they serve different purposes:

  • Transitions require a trigger (hover, focus, class change) and move between two states — a start and an end.
  • Animations (using @keyframes) can run automatically without a trigger, loop, go through multiple steps, and play in reverse.

Use a transition when reacting to user interaction. Use an animation when you need something to move on its own, repeat, or follow a multi-step path. The two can also be combined — for example, a button that animates on page load and then transitions on hover.

Common Mistakes to Avoid

  • Forgetting the duration: A transition with no transition-duration does nothing — the change will still be instant.
  • Putting transition on the wrong selector: Always put transition on the base state, not the :hover state. If you put it on :hover, the transition only plays when entering, not when leaving.
  • Using all carelessly: transition: all catches every property change including ones you didn't intend, and can affect performance.
  • Animating layout properties: Transitioning width, height, or padding causes reflow and is slower than using transform: scale().

Frequently Asked Questions

Can I transition display: none to display: block?

No. display is not animatable. To fade an element in or out, use opacity combined with visibility, or control opacity with a class toggle and keep the element in the layout.

What is the difference between transition and animation in CSS?

A transition reacts to a state change (like a hover) and moves between two values. An animation uses @keyframes, can loop, run automatically without a trigger, and supports multiple steps — not just start and end.

How do I make a transition work on page load?

Transitions only fire when a property changes. On page load, there is no change, so nothing fires. To trigger an animation on load, use CSS @keyframes or toggle a class with JavaScript after the page loads.

Which CSS transition timing function should I use?

ease-out is the best default for most UI interactions — it feels natural because it mimics how real objects decelerate. Use ease-in when something is exiting the screen, and linear only for things like progress bars or spinners.

Can CSS transitions be triggered by JavaScript?

Yes. Any property change triggers a transition — including changes made by JavaScript. Adding or removing a CSS class that changes a property value will cause the transition to fire. This is one of the most common patterns for building interactive UI components.

Does transition work on pseudo-elements like ::before and ::after?

Yes. You can apply transition to ::before and ::after pseudo-elements in the same way you would any other element. This is useful for animated underlines, icon swaps, and decorative effects.