Skip to content

Intermediate · CSS layout and responsive design · topic 29 of 64 · 25 min

Transitions and animations

Explanation

Transitions animate a change smoothly, for example a button colour on hover. Animations with @keyframes can run on their own, like a loading spinner. Animate transform and opacity for smooth results, keep motion short, and respect users who ask for reduced motion.

Transitions

A transition tells the browser: when this property changes, do not jump; move smoothly over some time. You write it on the normal state, and it works both ways (in and out).

css
.btn {
  background: #2563eb;
  transition: background-color 200ms ease, transform 200ms ease;
}
.btn:hover,
.btn:focus-visible {
  background: #1d4ed8;
  transform: translateY(-2px);
}
A button that lifts slightly on hover and keyboard focus

The parts are: which property, how long (200ms is a good default for small changes), and the easing (how speed changes: ease, ease-out, linear).

Think of it like this: Think of a dimmer switch versus a normal switch. A normal switch makes the light jump on; a dimmer brings it up gently. A transition is a dimmer for CSS changes.

Transforms

TransformEffect
translate(10px, 0)Move without affecting the layout around it
scale(1.05)Grow or shrink
rotate(45deg)Turn

Keyframe animations

css
@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.spinner {
  width: 32px;
  height: 32px;
  border: 4px solid #e5e7eb;
  border-top-color: #2563eb;
  border-radius: 50%;
  animation: spin 800ms linear infinite;
}
A loading spinner made only with CSS

@keyframes describes the steps of an animation (from/to, or percentages like 0%, 50%, 100%). The animation property connects it to an element with a name, a duration, an easing and how many times to repeat.

Smooth and kind motion

  • Animate transform and opacity: the browser can move them without recalculating the layout, so they stay smooth even on cheap phones.
  • Avoid animating width, height, top or left on big elements; they cause jank (stuttering).
  • Keep UI motion short: 150 to 300ms for most changes.
  • Motion should explain something (where a menu came from), not just decorate.
css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
Turn motion off for people who asked for it in their device settings
Tip: Give hover effects to :focus-visible too, so keyboard users get the same feedback as mouse users.
Careful: Flashing content (more than three flashes per second) can trigger seizures. Never make anything blink quickly.

Watch the lesson

Transitions and animations · 1/6

Motion = feedback

Motion helps users understand changes, when it is short and gentle.

Prefer a video by a teacher? Find free videos on “css transitions animations keyframes tutorial” on YouTube ↗

In real life: Add-to-cart feedback

When you tap "Add" on a grocery app, the button briefly scales to 0.95 and back with a 150ms transition, and the cart icon count fades in. A spinner made with @keyframes shows while the order is placed. Users who turned on "Remove animations" in Android accessibility settings get the same information without motion, thanks to prefers-reduced-motion.

Practice (0/2 done)

Task 1 · Code · HTML

Give .btn a transition on transform lasting 200ms, and on .btn:hover set transform: scale(1.05).

Task 2 · Code · HTML

Make a spinner: define @keyframes spin that rotates to 360deg, give .spinner the animation "spin 1s linear infinite", and add a prefers-reduced-motion: reduce media query that sets .spinner animation to none.

Quick quiz

Question 1

1.Where do you put the transition property?

Question 2

2.Which properties are the smoothest to animate?

Question 3

3.What is a good duration for a button hover effect?

Question 4

4.What does @media (prefers-reduced-motion: reduce) detect?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Modern CSS: variables, clamp, container queries and more