CSS @keyframes and Animation Shorthands Explained

CSS animations let you move, fade, resize, and otherwise change elements over time without writing script. This article explains how @keyframes defines the animation itself and how the animation shorthand controls timing, repetition, and playback.

Quick answer: Use @keyframes to describe the animation steps, then apply it with animation-name or the animation shorthand. The shorthand can set duration, timing function, delay, iteration count, direction, fill mode, and play state in one declaration.

Difficulty: Beginner

You’ll understand this better if you know: basic CSS selectors, how declarations work, and the difference between a class and a property value.

1. What Is CSS @keyframes and Animation Shorthands?

@keyframes is the CSS rule that defines the stages of an animation. The animation shorthand is the compact way to apply that animation to an element.

2. Why CSS Animations Matter

Animations help users notice important changes, understand state transitions, and make interfaces feel responsive. Common examples include loading spinners, alert attention states, success feedback, and subtle onboarding motion.

They matter because they can improve clarity when used well, but they can also distract if they are too flashy or too frequent. CSS animations are especially useful for changes that happen automatically or repeatedly.

3. Basic Syntax or Core Idea

The core pattern is simple: define the keyframes, then assign them to an element.

Defining keyframes

@keyframes pulse {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(1.1);
  }
}

This animation changes an element’s scale from normal size to slightly larger.

Applying the animation with the shorthand

.card {
  animation: pulse 1s ease-in-out infinite alternate;
}

In this example, the element uses the pulse keyframes, runs for one second, eases in and out, repeats forever, and alternates direction each time.

How the shorthand is interpreted

4. Step-by-Step Examples

Example 1: A fade-in animation

This is the simplest practical animation: start invisible, then become fully visible.

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.message {
  animation: fadeIn 300ms ease-out 1 both;
}

This fades the element in once and keeps the ending value because of both.

Example 2: Moving an element across the page

Transforms are a common animation target because they are smooth and predictable.

@keyframes slideRight {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(200px);
  }
}

.banner {
  animation: slideRight 2s linear 1 forwards;
}

The element moves from its original position to the right and stays there after the animation ends.

Example 3: Bouncing attention state

Repeated motion often uses infinite and alternate to create a back-and-forth loop.

@keyframes bounce {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-12px);
  }
  100% {
    transform: translateY(0);
  }
}

.indicator {
  animation: bounce 800ms ease-in-out infinite;
}

This creates a repeating motion that can draw attention to a live status or notification.

Example 4: Delayed entrance animation

Delays are useful when you want motion to start after the page is already visible.

@keyframes riseUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.panel {
  animation: riseUp 400ms ease-out 150ms 1 both;
}

The delay waits before starting, and both keeps the element hidden during the delay and visible after completion.

5. Practical Use Cases

6. Common Mistakes

Mistake 1: Using the animation name without defining @keyframes

An animation name in the shorthand does nothing unless a matching @keyframes rule exists. Beginners often write the property and expect motion without defining the actual steps.

Problem: The browser cannot animate because it has no keyframe rule to follow, so the element stays unchanged.

.box {
  animation: spin 1s linear infinite;
}

Fix: Define the named keyframes before using the shorthand.

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

.box {
  animation: spin 1s linear infinite;
}

The corrected version works because the browser now knows the start and end states to interpolate.

Mistake 2: Forgetting the duration in the shorthand

If you omit the duration, the animation usually becomes effectively invisible. The shorthand can still be syntactically valid, but the motion may run with the default duration of zero seconds.

Problem: The animation has no visible time span, so it appears not to work even though the name is correct.

.notice {
  animation: fadeIn ease-out 1 both;
}

Fix: Include an explicit duration, usually right after the animation name.

.notice {
  animation: fadeIn 250ms ease-out 1 both;
}

The fixed version animates because the browser now has a real time span to interpolate over.

Mistake 3: Expecting the final state without fill mode

By default, an animation returns the element to its original styles after it ends. Many developers expect the ending keyframe to remain visible, but that only happens when you use the right fill mode.

Problem: The animation finishes, then the element snaps back to its pre-animation style because fill-mode is not set.

@keyframes dropIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.toast {
  animation: dropIn 300ms ease-out 1;
}

Fix: Use forwards or both when you want the final keyframe to stay applied after the animation ends.

.toast {
  animation: dropIn 300ms ease-out 1 forwards;
}

The corrected version keeps the ending styles, so the element does not jump back unexpectedly.

7. Best Practices

Prefer transform and opacity for smooth motion

Browsers usually animate transform and opacity more efficiently than layout-affecting properties like width or top.

@keyframes fadeLift {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

This approach reduces layout work and tends to feel smoother.

Use the shorthand only when it improves readability

The shorthand is convenient, but very long values can become hard to scan. If a declaration is getting crowded, longhand properties may be clearer.

.modal {
  animation-name: fadeIn;
  animation-duration: 200ms;
  animation-timing-function: ease-out;
  animation-fill-mode: forwards;
}

This version makes each setting explicit, which helps when maintaining larger stylesheets.

Respect reduced-motion preferences

Animations should not overwhelm users who prefer less motion. Use the media query to provide a calmer experience.

@media (prefers-reduced-motion: reduce) {
  .card {
    animation: none;
  }
}

This keeps the interface accessible without removing the feature for everyone.

8. Limitations and Edge Cases

9. Practical Mini Project

Here is a small notification card that fades and rises into view using one keyframes rule and one shorthand declaration.

.notification {
  max-width: 320px;
  padding: 1rem;
  border-radius: 0.75rem;
  background: #1f2937;
  color: #fff;
  animation: toastIn 280ms ease-out 1 both;
}

@keyframes toastIn {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

This project demonstrates the full workflow: define a named animation, then apply it with timing, iteration, and fill behavior in one place.

10. Key Points

11. Practice Exercise

Expected output: The notice briefly highlights, then remains white after the animation ends.

Hint: You will need a duration, a fill mode, and a matching animation name.

@keyframes highlight {
  from {
    background-color: #fef3c7;
  }
  to {
    background-color: #ffffff;
  }
}

.notice {
  animation: highlight 500ms ease-out 1 forwards;
}

12. Final Summary

CSS @keyframes gives you the timeline of an animation, while the animation shorthand lets you apply that timeline with duration, easing, delay, direction, repetition, and fill behavior. Once you understand how those pieces fit together, most CSS animation work becomes a matter of choosing the right values rather than learning a new syntax.

For everyday UI work, start with simple fade and transform animations, keep motion purposeful, and use fill modes intentionally. If you want to go further, the next topic to study is how the individual animation longhands map back to the shorthand and how transitions differ from animations in CSS.