Lesson 16 / Motion
CSS Transitions
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.
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.
transitiondefines 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.
| Property | Controls | Example |
|---|---|---|
transition-property | What changes | opacity |
transition-duration | How long the change takes | 200ms |
transition-timing-function | How the speed changes during the transition | ease-out |
transition-delay | How long to wait before starting | 100ms |
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 Type | Examples | Guidance |
|---|---|---|
| Best for motion | opacity, transform | Usually smooth and efficient. |
| Usually okay | background-color, color, border-color, box-shadow | Good for visual feedback, but keep effects subtle. |
| Avoid for movement | width, height, top, left, margin, padding | Can trigger layout changes and feel less smooth. |
| Cannot transition directly | display | Use opacity, visibility, transform, or another pattern instead. |
State Changes That Trigger Transitions
| Trigger | Use For | Example |
|---|---|---|
:hover | Pointer hover feedback | Button lift or card highlight |
:focus-visible | Keyboard focus feedback | Accessible focus ring |
| Class changes | Reusable component states | .is-open, .is-visible, .is-active |
| Form states | Validation feedback | .has-error |
| JavaScript class toggle | Interactive UI | Menu 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 Function | Feel | Common Use |
|---|---|---|
linear | Same speed the whole time | Progress indicators or mechanical motion |
ease | Natural default curve | General UI feedback |
ease-in | Starts slow, ends fast | Elements leaving the screen |
ease-out | Starts fast, ends slow | Elements entering or settling |
cubic-bezier() | Custom curve | Advanced 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
| Mistake | Why It Hurts | Fix |
|---|---|---|
Using transition: all | Unexpected properties may animate | List the properties you actually want to transition. |
Trying to transition display | display switches on or off instantly | Use opacity, visibility, transform, or a layout-specific pattern. |
| Using very long durations | The interface can feel slow | Keep most UI transitions between 150ms and 300ms. |
| Animating layout properties | Can cause jank or layout recalculation | Prefer transform and opacity for movement. |
| Only designing hover states | Keyboard and touch users may miss feedback | Include :focus-visible and class-based states. |
| Skipping reduced motion | Some users are sensitive to motion | Add 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-colorandtransform. - Add a clear
:focus-visibletransition for keyboard users. - Build a menu that opens and closes by toggling an
.is-openclass. - Create a fade in/out pattern with
.is-visible. - Add a
prefers-reduced-motionfallback. - Compare
linear,ease, andease-outon the same transition. - Refactor one
transition: allexample into a specific property list.
Resources
- MDN CSS Transitions Web Docs
- W3Schools CSS transitions