The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Choose transitioned properties.button { transition-property: background-color, transform; }View examples
Set transition duration.button { transition-duration: 160ms; }View examples
Declare a transition.button { transition: transform 160ms ease-out; }View examples
Transition several properties.card { transition: transform 180ms ease-out, box-shadow 180ms ease-out; }View examples
Delay a transition.item { transition-delay: 80ms; }View examples
Use custom easing.panel { transition-timing-function: cubic-bezier(.2, .8, .2, 1); }View examples
Use stepped timing.sprite { transition-timing-function: steps(6, end); }View examples
Define keyframes@keyframes fade-in { from { opacity: 0; } to { opacity: 1; }; }View examples
Run a keyframe animation.notice { animation: fade-in 240ms ease-out; }View examples
Add intermediate keyframes@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; }; }View examples
Repeat an animation.spinner { animation-iteration-count: infinite; }View examples
Alternate direction.indicator { animation-direction: alternate; }View examples
Retain the final keyframe.enter { animation-fill-mode: forwards; }View examples
Pause an animation.carousel:hover { animation-play-state: paused; }View examples
Move with transform.card:hover { transform: translateY(-.25rem); }View examples
Fade with opacity.popover[data-open="true"] { opacity: 1; }View examples
Honor reduced motion@media (prefers-reduced-motion: reduce) { .animated { animation: none; transition-duration: .01ms; }; }View examples
Preserve a clear focus state.button:focus-visible { outline: .2rem solid currentColor; outline-offset: .2rem; }View examples

Use transitions when a property changes between states and keyframe animations when motion needs its own timeline. Animate only properties that clarify feedback or relationships, keep controls usable when motion is absent, and provide a reduced-motion path for nonessential effects.

Step by step

Detailed examples

01

Transition explicit state changes

A transition begins when an element's computed value changes and the old and new values are transitionable. Name the properties rather than using all, which can animate future changes unintentionally. The first time value is duration and the optional second time is delay; comma-separated lists pair definitions by position.

Button feedback with explicit properties
.button {
  background: #2563eb;
  transform: translateY(0);
  transition: background-color 160ms ease-out,
              transform 160ms ease-out;
}
.button:hover {
  background: #1d4ed8;
  transform: translateY(-.125rem);
}
Back to quick reference ↑
02

Match easing and delay to the interaction

Timing functions map elapsed time to progress. ease-out often suits elements entering or reacting because it starts quickly and settles; linear suits mechanically constant progress; steps is useful for frame-like changes. Long delays can make interfaces feel broken, and staggered delays should not postpone access to important information.

Custom and stepped timing
.panel {
  transition: transform 220ms cubic-bezier(.2, .8, .2, 1) 40ms;
}
.sprite {
  transition: background-position 600ms steps(6, end);
}
Back to quick reference ↑
03

Define a timeline with keyframes

@keyframes creates a named set of offsets; from and to equal 0% and 100%. Properties omitted at an offset are interpolated from the element's underlying style or neighboring keyframes where possible. Applying animation-name alone has no visible duration because the initial duration is zero, so set timing explicitly.

Enter and settle
@keyframes enter {
  from { opacity: 0; transform: translateY(.5rem); }
  70% { opacity: 1; transform: translateY(-.0625rem); }
  to { opacity: 1; transform: translateY(0); }
}
.notice { animation: enter 240ms ease-out; }
Back to quick reference ↑
04

Control repetition, direction, and applied endpoints

iteration-count controls repetitions and may be fractional; infinite motion should be reserved for genuine ongoing activity. alternate avoids a discontinuous jump between end and start. fill-mode changes which keyframe styles apply outside the active interval, but forwards is not a substitute for setting the element's durable end state in application logic.

A reversible activity indicator
@keyframes breathe {
  from { opacity: .45; transform: scale(.96); }
  to { opacity: 1; transform: scale(1); }
}
.indicator {
  animation: breathe 900ms ease-in-out infinite alternate;
}
Back to quick reference ↑
05

Expose a way to pause persistent motion

animation-play-state pauses or resumes without resetting elapsed progress. Pause controls are preferable to hover-only pausing because hover is unavailable to many users and devices. If motion begins automatically and lasts more than a brief period, provide an operable control and persist the user's choice where appropriate.

Pause a decorative animation with a real control
<div class="banner animated" data-paused="false">System status</div>
<button type="button" id="motion-toggle">Pause animation</button>
<script>
  const banner = document.querySelector('.banner');
  const button = document.querySelector('#motion-toggle');
  button.addEventListener('click', () => {
    const paused = banner.dataset.paused !== 'true';
    banner.dataset.paused = String(paused);
    button.textContent = paused ? 'Resume animation' : 'Pause animation';
  });
</script>
<style>
.animated { animation: breathe 900ms ease-in-out infinite alternate; }
.animated[data-paused="true"] { animation-play-state: paused; }
</style>
Back to quick reference ↑
06

Prefer motion that does not relayout surrounding content

transform and opacity can often be composited efficiently and do not alter the document's layout geometry. Animating dimensions or positional layout properties may trigger repeated layout and paint work and can move neighboring content. Performance still depends on element size, effects, and device, so profile real pages rather than treating any property as free.

Popover visibility and card lift
.popover {
  opacity: 0;
  transform: translateY(-.25rem);
  pointer-events: none;
  transition: opacity 140ms ease-out, transform 140ms ease-out;
}
.popover[data-open="true"] {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.card { transition: transform 180ms ease-out; }
.card:hover { transform: translateY(-.25rem); }
Back to quick reference ↑
07

Keep meaning and focus independent from motion

prefers-reduced-motion:reduce indicates a request to minimize nonessential movement. Replace large travel, parallax, pulsing, and automatic loops with immediate or subtle state changes while preserving essential progress feedback. Never use animation alone to communicate focus, validation, or completion; retain text, color-independent markers, and visible focus outlines.

Reduced-motion alternative
.animated { animation: enter 240ms ease-out; }
.button { transition: transform 160ms ease-out; }
.button:focus-visible {
  outline: .2rem solid currentColor;
  outline-offset: .2rem;
}

@media (prefers-reduced-motion: reduce) {
  .animated { animation: none; }
  .button { transition-duration: .01ms; }
}
Back to quick reference ↑

Local code tester

Try CSS transitions and animations

Change transition timing, keyframes, pause state, and reduced-motion overrides in a local preview.

Runs in your browser
Preview

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. World Wide Web ConsortiumCSS Transitions Module Level 2w3.org
  2. World Wide Web ConsortiumCSS Animations Level 1w3.org
  3. MDN Web DocsUsing CSS transitionsdeveloper.mozilla.org
  4. MDN Web DocsUsing CSS animationsdeveloper.mozilla.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback