Choreographing the Web: A Deep Dive into CSS @keyframes
While CSS Transitions are perfect for simple state changes (like a hover effect), **`@keyframes`** are the engine for creating complex, multi-step animations. They give you the power to act as a director, dictating exactly what an element should be doing at any point during its timeline. This article dives deep into the `@keyframes` rule and its powerful companion, the `animation` property.
Section 1: The Core Syntax of @keyframes
The `@keyframes` at-rule is a block of code that defines the animation. You give it a unique name, and then define "keyframes" (or steps) inside it using percentages, or the keywords `from` and `to`.
Using `from` and `to`
For a simple, two-step animation, `from` (the starting state, or `0%`) and `to` (the ending state, or `100%`) are the most straightforward.
/* This animation will fade an element in */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}Using Percentages
For more than two steps, percentages are required. You can add as many as you like, from `0%` to `100%`, to create complex sequences.
/* This animation creates a 'pulse' effect */
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}You can even group selectors. The `pulse` animation above is more efficiently written by grouping the `0%` and `100%` states, since they share the same styles: `0%, 100% transform: scale(1);`.
Section 2: Applying Your Animation
Defining a `@keyframes` rule does nothing on its own. You must apply it to an element using the `animation` properties. While you can use the `animation` shorthand, it's crucial to understand the long-form properties it controls.
- `animation-name`: Specifies the name of the `@keyframes` rule to apply (e.g., `fadeIn`).
- `animation-duration`: Sets the length of time the animation takes to complete one cycle (e.g., `2s` or `500ms`). **This is required.**
- `animation-timing-function`: Controls the speed curve of the animation. Common values are `linear`, `ease`, `ease-in`, `ease-out`, `ease-in-out`, `steps()`, and the advanced `cubic-bezier()` function.
- `animation-delay`: Sets a delay before the animation begins (e.g., `1s`).
- `animation-iteration-count`: Defines how many times the animation should run. Use a number (e.g., `3`) or the keyword `infinite` to loop it forever.
- `animation-direction`: Sets whether the animation should play forwards, backwards, or alternate. Values: `normal`, `reverse`, `alternate`, `alternate-reverse`.
- `animation-fill-mode`: This is a critical property. It defines what styles apply to the element *before* the animation starts and *after* it ends.
- `none` (default): Element is styled as-is, then animates, then reverts to its original style.
- `forwards`: After the animation finishes, the element will retain the styles from the *last keyframe* (`100%`).
- `backwards`: Before the animation starts (during a delay), the element will adopt the styles from the *first keyframe* (`0%`).
- `both`: Applies the rules for both `forwards` and `backwards`.
- `animation-play-state`: Allows you to pause (`paused`) and resume (`running`) an animation, often controlled with JavaScript.
The `animation` Shorthand
It's much more common to use the `animation` shorthand. The order is important, though modern browsers are quite good at parsing it. A common pattern is:
/* [name] [duration] [timing-function] [delay] [iteration-count] [direction] [fill-mode] */
.my-element {
animation: pulse 2s ease-in-out 1s infinite alternate forwards;
}Section 3: Performance and Accessibility
Hardware Acceleration for Smooth Animations
Not all properties are cheap to animate. Animating properties like `width`, `height`, `left`, `top`, or `margin` forces the browser to "re-layout" the page, which is slow and can cause janky, stuttering animations.
For best performance, stick to animating properties that the browser's GPU can handle:
- `transform` (e.g., `translateX()`, `scale()`, `rotate()`)
- `opacity`
❌ Bad (Slow)
@keyframes slide {
from { left: 0; }
to { left: 100px; }
}Animates `left`, causing layout reflows.
✔️ Good (Fast)
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(100px); }
}Animates `transform`, which is GPU-accelerated.
Accessibility: `prefers-reduced-motion`
Some users experience motion sickness or vestibular disorders from large movements. It is a crucial accessibility best practice to respect their preference by disabling or reducing animations inside a `prefers-reduced-motion` media query.
/* Standard animation */
.my-element {
animation: slide-in 1s ease-out;
}
/* Disable animations for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
.my-element {
animation: none;
}
}Key Takeaway: `@keyframes` are the most powerful tool in your CSS animation arsenal. By combining them with the `animation` properties, you can create anything from subtle pulses to complex, cinematic sequences. Always prioritize `transform` and `opacity` for performance, and respect `prefers-reduced-motion` for accessibility.