webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Tooling
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Forms
  12. 12Data and backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animations
  16. 16Testing
  17. 17Architecture
CSS · Lesson 7 of 8

Transitions and animations

transition vs @keyframes, easing, what's cheap to animate, prefers-reduced-motion.

Updated

What transitions and animations are

Motion in an interface has a job, it's not decoration: it shows what changed, where an element comes from and that your action had an effect. CSS gives you two tools:

Transition Animation (@keyframes)
Starts when a property changes (hover, a new class) on its own, on appearance, or in a loop
States from A to B any number of steps (0%, 50%, 100%)
When hover, focus, open / close, feedback loaders, page entrances, attention cues

Transition

.btn {
  transition: background-color 150ms ease, transform 150ms ease;
}
.btn:hover {
  background-color: var(--accent-hover);
  transform: translateY(-1px);
}

transition: <property> <duration> <easing> <delay>. Avoid transition: all — it also animates properties you don't want (and it costs).

@keyframes and animation

@keyframes fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.toast {
  animation: fade-in 200ms ease-out both;
}
Property Role
animation-duration how long it lasts
animation-timing-function the speed curve
animation-iteration-count how many times (infinite for a loader)
animation-fill-mode: both keeps the start style before and the end style after

Easing — the speed curve

Easing Feel When
ease-out starts fast, slows down elements that appear — the most natural
ease-in starts slow, speeds up elements that disappear
ease-in-out slow – fast – slow moving from one place to another
linear constant rotations, progress, loaders

Durations: 100–200 ms for feedback (hover), 200–300 ms for entrances, rarely over 400 ms. Long animations make the interface feel slow.

What to animate — performance

Animate only transform and opacity: they're computed on the GPU, without layout. width, height, top, margin trigger layout on every frame → a choppy animation. The explanation is in How the browser renders.

Instead of Use
left: 0 → 100px transform: translateX(100px)
width: 0 → 100% (a progress bar) transform: scaleX(0 → 1)
display: none ↔ block opacity + visibility, or @starting-style

Respect the user's preference

Some people get motion sickness or have vestibular sensitivity and turn on "reduce motion" in their system. Mandatory:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

In Tailwind: motion-safe:animate-… / motion-reduce:transition-none.

Modern: appearing from display: none

.dialog[open] {
  opacity: 1;
  transition: opacity 200ms, display 200ms allow-discrete;
  @starting-style { opacity: 0; }
}

@starting-style defines the "before appearing" state — you can animate elements that just switched from display: none. For transitions between pages there's the View Transitions API.

Going further

For animations in React (Motion), timelines and scroll (GSAP) and complete examples, see the Animations topic.

Summary

  • Transition = from A to B on a change; animation = @keyframes, starts on its own.
  • ease-out on entrance, 150–300 ms; only transform and opacity.
  • prefers-reduced-motion is mandatory.

Official sources

Exercises

Was this page helpful?

One tap — no account needed.