CSS Animations @keyframes
Define @keyframes, control duration, easing, iteration, and fill-mode — when to animate, what to animate, and reduced-motion defaults.
- css
- animations
- keyframes
Transitions interpolate when a property changes. Animations run a timeline you declare with @keyframes, optionally looping, reversing, or finishing in an end state without a matching “to” style on the element. Use animations for loaders, entrance choreography, and continuous motion; use transitions for hover/focus state changes.
Docs: MDN CSS animations, @keyframes, animation.
Anatomy
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.85;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.badge-live {
animation: pulse 1.6s ease-in-out infinite;
}
Longhand you’ll actually touch:
| Property | Role |
|---|---|
animation-name |
@keyframes name |
animation-duration |
Length of one cycle |
animation-timing-function |
Easing across the cycle (or per keyframe) |
animation-delay |
Wait before start |
animation-iteration-count |
Number or infinite |
animation-direction |
normal | reverse | alternate … |
animation-fill-mode |
Styles before/after (none/forwards/backwards/both) |
animation-play-state |
running | paused |
Shorthand order (common):
animation: name duration timing-function delay iteration direction fill-mode;
One-shot enter with fill-mode
@keyframes fade-up {
from {
opacity: 0;
transform: translateY(0.5rem);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.toast {
animation: fade-up 200ms ease-out both;
}
both (or forwards) keeps the end keyframe styles after the animation finishes. Without it, the element can snap back to the underlying CSS — a classic “why did my modal flash” bug.
What to animate
Prefer compositor-friendly properties: transform, opacity (and in some engines filter). Animating width, height, top, or margin triggers layout and often jank.
/* Prefer */
.drawer {
transform: translateX(100%);
transition: transform 200ms ease;
}
.drawer.is-open {
transform: translateX(0);
}
/* Avoid for 60fps UI */
.drawer-slow {
animation: widen 200ms forwards;
}
@keyframes widen {
from { width: 0; }
to { width: 20rem; }
}
Multiple animations
.hero-mark {
animation:
fade-up 400ms ease-out both,
float 4s ease-in-out 400ms infinite;
}
Comma-separate full animation lists. Debugging: temporarily disable one name in DevTools Animations panel.
Reduced motion
@media (prefers-reduced-motion: reduce) {
.badge-live,
.toast,
.hero-mark {
animation: none;
}
}
Or provide a calmer alternate (opacity-only, shorter, single iteration). Decorative loops should die under reduced motion; essential status may stay as a non-animated text/state change.
JS coordination
el.addEventListener("animationend", (e) => {
if (e.animationName === "fade-up") el.remove();
});
Use animationend / animationiteration carefully with multiple animations — check animationName.
Interview out-loud
“@keyframes defines intermediate styles over a percentage timeline. I attach them with the animation shorthand, use fill-mode: forwards/both so end states stick, and prefer transform/opacity for performance. Transitions are for state changes; animations are for orchestrated or looping motion. I gate decorative motion behind prefers-reduced-motion.”
Footguns
- Forgetting
forwardsand seeing a snap-back. - Infinite animations on large filtered layers — battery and GPU cost.
- Animating from
display: none— won’t run; toggle a class after showing, or use WAAPI/@starting-stylepatterns carefully. - Easing on stepped spinners — use
steps()or linear for loaders. - Relying on animation for critical info with no static equivalent.
Related
Further reading
Related guides
- scroll-driven Animations IntroCSS scroll-driven animations — animation-timeline with scroll() and view(), progress-linked effects, support caveats, and reduced motion.
- Accent Color and Form ControlsUse accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.
- BEM Naming MethodologyBlock, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.
- blend-mode Basicsmix-blend-mode vs background-blend-mode — how pixels combine, isolation, and the stacking/readability traps in product UI.