CSS Animations: Transitions vs. Keyframes

Abstract image used to represent CSS Animations: Transitions vs. Keyframes
Image by Jr Korpa.

CSS animations are a powerful tool for creating engaging, interactive web experiences. Whether it's a subtle button hover effect or a complex loading spinner, animations enhance user interaction and bring a sense of liveliness to a website. But when it comes to CSS, there are two primary ways to implement animations: transitions and @keyframes.

In this article, I intend to explore both methods, their strengths and use cases, and perhaps touch on performance considerations to help you make more informed decisions when animating your web projects.


CSS Transitions: The Simple Approach

I've written about CSS transitions in detail before. They allow you to animate changes between two element states, like interactions triggered by pseudoclasses like :hover, or by adding or changing a classname or parent context. They are quick to implement and are best suited for simple, statebased animations.

How Transitions Work

CSS transitions require a starting state, an ending state, and a trigger (e.g., hover, focus). We rely entirely on the browser to automatically calculate and undertake the animation between the styling of those two states.

Example: Button Hover Effect

button {
  background-color: #3498db;
  color: white;
  transition: background-color 0.3s ease, color 0.3s ease;
}

button:hover {
  background-color: #2ecc71;
  color: black;
}

When the user hovers over the button, the background and text colour smoothly transition over 0.3 seconds between the two states.

When to Use Transitions

  • Simple, twostate animations.
  • Interactions like hover, focus, or active effects.
  • When you want lightweight, easytoread code.

You will in fact find my personal website quite literally littered with transitionbased animations there isn't a single @keyframes animation anywhere on my website (at the time of writing anyway).


@keyframes: Advanced Animations

I have of course also written about @keyframes animations in detail before.

For more complex animations that might require multiple steps or states, or repeat over time, the @keyframes rule is your tool of choice. Keyframes define how an element should look at different points during the animation sequence, whilst allowing the browser to animate between them.

How @keyframes Work

A keyframes animation is defined in two parts:

  1. The @keyframes block, where the animation steps are specified.
  2. The animation property, which applies the animation to an element.

Example: A Loading Spinner

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.loader {
  display: inline-block;
  width: 50px;
  height: 50px;
  border: 5px solid #3498db;
  border-top: 5px solid transparent;
  border-radius: 50%;
}

@media (prefers-reduced-motion: no-preference) {
  .loader {
    animation: spin 1s linear infinite;
  }
}

The spinner rotates continuously when the browser supports prefers-reduced-motion and reports no-preference. It stays still when reduced motion is requested or the media feature is unsupported. Keep a visible loading message alongside it, for example <p role="status"><span class="loader" aria-hidden="true"></span> Loading…</p>, so the state is clear without movement. Update the message when the operation finishes. Safari 10.1 supports the motion preference; check the other browser versions your project needs.

When to Use Keyframes

  • Complex animations with multiple steps or states.
  • Continuous animations, like loaders or spinners.
  • Animations that require finer control over timing and properties.

Performance Considerations

Animations can impact performance, especially on resourceconstrained devices like older mobile phones or even TVs. Here are some tips for smooth and efficient animations:

  • Choose properties carefully:

    transform and opacity can often be composited without recalculating layout or painting each frame. The browser decides how to do that work; GPU acceleration and smooth playback are not guaranteed. Measure the actual animation on the devices you support.
  • Avoid unnecessary layout work:

    Animating width, height, or top can trigger layout work. If you only need to move something visually, consider a transform such as translateX() instead.
  • Limit Simultaneous Animations

    : Too many animations running at once can overwhelm the browser, leading to lag.
  • Avoid Animations during Repeated Events

    : This is more of a JavaScript concern, perhaps, but if you can, avoid scenarios where you are animating whilst the browser is doing something else strenuous, like scrolling.

Wrapping Up

CSS offers two main animation tools, but they are quite different from one another. transition is used for simple, statebased changes, whilst @keyframes allows us to build up complex, timelinebased, multistep animations.

Key Takeaways

  • Transitions

    are Ideal for simple, twostate animations triggered by user interaction.
  • Keyframes

    are better for complex or continuous animations with multiple steps.
  • Performance matters: prefer transform and opacity where they fit the effect, then check the resulting rendering work and playback.

When used thoughtfully, CSS animations can elevate a user's experience whilst keeping our web projects performant and engaging.


Need a senior engineer involved?

I can work directly in the codebase, review the architecture, or support the team through delivery when the work needs more than extra hands.