Skip to main content
Syllabus
On this page

CSS Transitions: Smooth State Changes with transition, @starting-style and allow-discrete

Badar KhalilUpdated September 30, 2026 5 min read

What are CSS transitions?

CSS transitions let the browser animate a property from its old value to its new value over a set time, instead of changing instantly. They are the simplest way to add motion to hover effects, focus rings, menus, cards, buttons and UI state changes. A transition needs only two things: a start state, an end state, and a rule telling the browser how long the change should take.

Focus keyword: CSS transitions. Related trending keywords: transition-behavior allow-discrete, @starting-style, interpolate-size, linear() easing, CSS micro-interactions, GPU accelerated animation, smooth hover effects.

The four transition longhand properties

  • transition-property: which property to animate (opacity, transform, background-color, or all).
  • transition-duration: how long it takes (200ms, 0.3s). Default is 0s, which means no transition.
  • transition-timing-function: the speed curve (ease, linear, ease-in, ease-out, ease-in-out, cubic-bezier(), steps(), linear()).
  • transition-delay: wait time before starting (100ms). Negative delays start part-way through.

The shorthand is transition: property duration timing-function delay. You can chain several transitions with commas: transition: opacity .3s ease, transform .3s ease-out .05s;. A fifth longhand, transition-behavior, is covered below.

Put the transition on the base state

Declare the transition on the element's normal rule, not only on :hover. If it only exists on :hover, the element animates in but snaps back instantly when the pointer leaves. Declaring it on the base state makes both directions smooth. You can also give the return direction a different speed by setting another transition in the hover rule.

Timing functions and easing

  • ease (default): slow start, fast middle, slow end.
  • ease-out: fast start, gentle stop. Best for elements entering the screen.
  • ease-in: slow start, fast end. Best for elements leaving.
  • cubic-bezier(x1, y1, x2, y2): custom curve. Y values can go beyond 0 to 1 for overshoot (bounce-like) effects.
  • steps(n): jumps in n discrete steps, useful for sprite or typewriter effects.
  • linear(...): a modern easing function that takes many points, so you can approximate springs and bounces in pure CSS. Example: linear(0, 0.5 25%, 1, 0.9 60%, 1). Generate long lists with an online linear() easing generator.

What can be transitioned?

Only properties with an interpolable value type can transition: numbers, lengths, percentages, colors, transforms, shadows, and similar. Classic examples include opacity, transform, color, background-color, width, box-shadow and filter. Keywords such as display and height: auto were historically not animatable, which is why developers used max-height hacks.

Modern features: allow-discrete, @starting-style and interpolate-size

  • transition-behavior: allow-discrete lets discrete properties like display and content-visibility take part in a transition. The value flips at the right moment, so an element can fade out before display: none is applied.
  • @starting-style defines the style an element transitions from on its first render, for example when it is added to the DOM or changes from display: none. This gives you entry animations with no JavaScript.
  • interpolate-size: allow-keywords (set on :root) lets you transition to and from intrinsic sizes like height: auto, min-content and fit-content. Use it as progressive enhancement, since support is not universal yet.

Best practices

  • Prefer animating transform and opacity. They are usually handled by the compositor and stay smooth. Animating width, height, top or left triggers layout and can cause jank.
  • Avoid transition: all in production. It animates properties you did not intend and can hurt performance. List properties explicitly.
  • Keep UI transitions short: about 150ms to 300ms for small controls, up to 500ms for larger movements.
  • Never rely on a transition alone to communicate state. Keep colors, text and ARIA states correct, and respect prefers-reduced-motion (see the last topic in this chapter).
  • Transitions fire only when a computed value changes. If an element is inserted with its final styles, nothing animates unless you use @starting-style.

Common mistakes

  • Forgetting units: transition: opacity 0.3 is invalid. Use 0.3s.
  • Putting the transition only in :hover so the un-hover snaps back.
  • Trying to transition between display: none and block without allow-discrete.
  • Expecting transitions to run on page load. They need a change after first render, or @starting-style.

Quick summary

Use CSS transitions for simple two-state motion. Reach for keyframe animations when you need multiple steps, looping or automatic playback. Try the interactive examples below and edit the code to see the result instantly.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Exercise: Add a smooth hover transition to a cardHTML

Make the card lift up by 6px, grow its shadow and change its background color on hover and focus-within. Use a transition on the base state only for transform, box-shadow and background-color (do not use transition: all). Keep the duration between 200ms and 300ms and use ease-out.

Try it Yourself HTML
Output

Press Run to execute.

Show expected output
The card smoothly lifts by 6px with a larger shadow and a new background color on hover, and smoothly returns when the pointer leaves.

This is a self-check — compare your result with the expected output above.

Was this page helpful?