Lesson 16 / Motion

CSS Transitions

Time
55 min
Type
Reading + Interactive
Level
Intermediate
Use
Core

Use CSS transitions to animate changes between interface states with smooth, accessible feedback.

Course Role

Core

Part of the main course path. Prioritize this before moving to optional polish or deeper references.

Teacher Notes / In-Class Use

Demo Live

  • Walk through the interactive demo before students start changing their own project files.
  • Connect the demo back to the first goal: Explain the CSS state change that makes a `transition` run

Try In Class

  • Create a button hover transition using `background-color` and `transform`.
  • Have students make one visible change, save, refresh, and explain what changed.

Submit Or Check

  • Ask students to show the work in the browser, not only in the editor.
  • Have students commit their progress with a clear message when the checkpoint is stable.

Watch For

  • Students copying code without checking file paths, spelling, or capitalization.
  • Visual changes that work locally but break when the project is published.

Learning Goals

  • Explain the CSS state change that makes a `transition` run
  • Create transitions with shorthand and individual `transition-*` properties
  • Choose transition-friendly properties while respecting accessibility and performance

Interactive Demo

How to use this demo.

Use the demo as a small lab. Change one thing, observe the result, then connect it back to your own project.

What To Try

  • Change the transitioned property, duration, delay, and easing.
  • Trigger the demo after each setting change and compare the feel.

What Changes

  • The motion changes without changing the layout structure.
  • The code sample updates with the transition settings.

What To Notice

  • Short, focused transitions usually feel better than slow decorative motion.
  • Opacity and transform are safer animation targets than layout-heavy properties.

Apply It

  • Add one small hover or focus transition to a button or link in your project.

Interactive Demo

Transition Timing Playground

Change the timing values, then trigger the preview. Transitions are about how a change feels between two states.

Change me

duration: 400ms / delay: 0ms / easing: ease

.box {
  transition: transform 400ms ease 0ms;
}

.box.is-active {
  transform: translateX(120px) scale(1.1);
}

What to notice

  • Duration changes how long the transition takes.
  • Delay changes when the transition begins.
  • Easing changes the personality of the motion.

Try this

  • Compare linear with ease-out.
  • Add a delay and notice how the interface feels less immediate.
  • Use transform or opacity for smoother motion.

This demo uses extra JavaScript for teaching. The code sample shows the pattern to practice. View full demo source.

Introduction

A CSS transition animates the change between two CSS states. Instead of jumping instantly from one value to another, the browser draws the in-between frames for you.

Transitions are useful for hover states, focus states, menus, accordions, alerts, form feedback, and small interface changes.

What Makes a Transition Happen

A transition needs a starting value, a changed value, and a transition rule that tells the browser how to animate between them.

  • The element starts with one CSS value, such as opacity: 0.
  • The value changes because of :hover, :focus-visible, .is-open, .is-visible, or another state.
  • The property can be transitioned.
  • transition defines the property, duration, timing function, and optional delay.

The Transition Properties

Transitions rely on four main properties. You can write them separately or combine them with the transition shorthand.

PropertyControlsExample
transition-propertyWhat changesopacity
transition-durationHow long the change takes200ms
transition-timing-functionHow the speed changes during the transitionease-out
transition-delayHow long to wait before starting100ms

Transition Shorthand

The shorthand pattern is transition: property duration timing-function delay. The delay is optional.

List the specific properties you want to animate. Avoid transition: all because it can animate unexpected properties and make debugging harder.

.button {
  transition: background-color 180ms ease, transform 180ms ease;
}

Individual Properties

Writing each transition property separately can be helpful when you are learning or when the timing needs to be very explicit.

.fade {
  transition-property: opacity;
  transition-duration: 200ms;
  transition-timing-function: ease-out;
}

Good Properties to Transition

Some properties are smoother and safer to transition than others. As a general rule, prefer properties that do not force the browser to recalculate layout.

Property TypeExamplesGuidance
Best for motionopacity, transformUsually smooth and efficient.
Usually okaybackground-color, color, border-color, box-shadowGood for visual feedback, but keep effects subtle.
Avoid for movementwidth, height, top, left, margin, paddingCan trigger layout changes and feel less smooth.
Cannot transition directlydisplayUse opacity, visibility, transform, or another pattern instead.

State Changes That Trigger Transitions

TriggerUse ForExample
:hoverPointer hover feedbackButton lift or card highlight
:focus-visibleKeyboard focus feedbackAccessible focus ring
Class changesReusable component states.is-open, .is-visible, .is-active
Form statesValidation feedback.has-error
JavaScript class toggleInteractive UIMenu open and close

Button Hover Transition

Hover transitions should be quick and focused. The goal is feedback, not a big animation moment.

.button {
  background-color: #2f9e44;
  transform: translateY(0);
  transition: background-color 180ms ease, transform 180ms ease;
}

.button:hover {
  background-color: #237a35;
  transform: translateY(-2px);
}

Focus-visible Transition

focus-visible helps keyboard users see where they are on the page. Do not remove focus styles without replacing them with a clear custom style.

.button {
  outline: 2px solid transparent;
  outline-offset: 0.25rem;
  transition: outline-color 160ms ease, box-shadow 160ms ease;
}

.button:focus-visible {
  outline-color: currentColor;
  box-shadow: 0 0 0 0.25rem rgb(47 158 68 / 25%);
}

Fade In and Out

opacity transitions are useful for showing and hiding interface elements without an abrupt visual jump.

Remember that an element with opacity: 0 can still take up space and may still be interactive unless you manage visibility or pointer events.

.message {
  opacity: 0;
  visibility: hidden;
  transition: opacity 200ms ease, visibility 200ms ease;
}

.message.is-visible {
  opacity: 1;
  visibility: visible;
}

Menu Open and Close

Menus often combine opacity and transform so the menu can fade and slide without animating layout properties.

.menu {
  opacity: 0;
  transform: translateY(-0.5rem);
  transition: opacity 200ms ease, transform 200ms ease;
}

.menu.is-open {
  opacity: 1;
  transform: translateY(0);
}

Accordion Effects

height: auto does not transition cleanly because the browser cannot animate to an unknown automatic value.

One workaround is transitioning grid-template-rows between 0fr and 1fr while the inner content has overflow: hidden.

.accordion-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 240ms ease;
}

.accordion-panel.is-open {
  grid-template-rows: 1fr;
}

.accordion-content {
  overflow: hidden;
}

Transitions with JavaScript

JavaScript can trigger CSS transitions by adding or removing classes. This keeps the animation details in CSS and the interaction logic in JavaScript.

<button class="menu-toggle">Menu</button>
<nav class="menu">...</nav>

const button = document.querySelector('.menu-toggle');
const menu = document.querySelector('.menu');

button.addEventListener('click', () => {
  menu.classList.toggle('is-open');
});

Timing Functions

transition-timing-function controls the feel of the transition. Start with built-in values before reaching for custom curves.

Timing FunctionFeelCommon Use
linearSame speed the whole timeProgress indicators or mechanical motion
easeNatural default curveGeneral UI feedback
ease-inStarts slow, ends fastElements leaving the screen
ease-outStarts fast, ends slowElements entering or settling
cubic-bezier()Custom curveAdvanced custom motion

Custom Timing Functions

cubic-bezier() gives you custom control over the speed curve, but it can be hard to read at first. Use it only when a built-in timing function does not feel right.

.card {
  transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

Accessibility and Performance

Respect user motion preferences with @media (prefers-reduced-motion: reduce). This is especially important for movement, scaling, sliding, and zooming effects.

Transitions should support the interface. If a transition makes the interface feel slower or harder to use, shorten it or remove it.

@media (prefers-reduced-motion: reduce) {
  .button,
  .menu,
  .accordion-panel {
    transition: none;
  }
}

Common Mistakes

MistakeWhy It HurtsFix
Using transition: allUnexpected properties may animateList the properties you actually want to transition.
Trying to transition displaydisplay switches on or off instantlyUse opacity, visibility, transform, or a layout-specific pattern.
Using very long durationsThe interface can feel slowKeep most UI transitions between 150ms and 300ms.
Animating layout propertiesCan cause jank or layout recalculationPrefer transform and opacity for movement.
Only designing hover statesKeyboard and touch users may miss feedbackInclude :focus-visible and class-based states.
Skipping reduced motionSome users are sensitive to motionAdd a prefers-reduced-motion fallback.

Checkpoint

Before moving on, make sure these feel true.

  • I can explain the main concept in my own words.
  • I can apply this lesson to my current project.
  • I can verify the result in the browser.
  • I can commit the change with a clear message.

Project Connection

This lesson supports current class projects.

Practice

  • Create a button hover transition using background-color and transform.
  • Add a clear :focus-visible transition for keyboard users.
  • Build a menu that opens and closes by toggling an .is-open class.
  • Create a fade in/out pattern with .is-visible.
  • Add a prefers-reduced-motion fallback.
  • Compare linear, ease, and ease-out on the same transition.
  • Refactor one transition: all example into a specific property list.

Resources

  • MDN CSS Transitions Web Docs
  • W3Schools CSS transitions