@keyframes rule
@keyframes defines the sequence of styles that change during a CSS animation. You specify keyframes as percentages (0%, 50%, 100%) or keywords (from, to), and the browser interpolates between them. Understanding keyframes is essential for creating smooth, complex animations.
Basic @keyframes syntax
CSS
<!-- @keyframes: define animation sequence -->
@keyframes fade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.element {
animation: fade 1s;
}
<!-- Element fades in over 1 second -->
/* Keyword syntax: from/to -->
@keyframes slide {
from {
transform: translateX(-100px);
}
to {
transform: translateX(0);
}
}
<!-- Element slides from left -->
/* Multiple keyframes: percentages -->
@keyframes bounce {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-50px);
}
100% {
transform: translateY(0);
}
}
<!-- Element bounces: up then down -->
/* Named animation: any name works -->
@keyframes my-custom-animation {
/* ... */
}
@keyframes slideUp {
/* ... */
}
<!-- Names can be dashed or camelCase -->Keyframe percentages
Percentage | Meaning | Common Use |
|---|---|---|
0% | Start state | Initial appearance |
50% | Middle state | Intermediate effect |
100% | End state | Final appearance |
0%, 100% | Same state | Loop start/end match |
CSS
<!-- Smooth color transition -->
@keyframes color-shift {
0% {
background: red;
}
50% {
background: blue;
}
100% {
background: green;
}
}
<!-- Smoothly transitions red -> blue -> green -->
/* Multiple properties at keyframes -->
@keyframes complex {
0% {
opacity: 0;
transform: translateY(20px);
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
transform: translateY(0);
}
}
<!-- Fade and move simultaneously -->
/* Different properties at different points -->
@keyframes staggered {
0% {
transform: translateX(0);
opacity: 1;
}
50% {
transform: translateX(100px);
opacity: 1;
}
75% {
transform: translateX(100px);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 0;
}
}
<!-- Move, pause, fade, return -->
/* Keyframes skip intermediate states -->
@keyframes quick-pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.3;
}
}
<!-- Pulse: bright -> dim -> bright -->Practical @keyframes animations
CSS
<!-- Fade in -->
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.element {
animation: fadeIn 1s;
}
<!-- Fades in -->
/* Slide in from left -->
@keyframes slideInLeft {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
.panel {
animation: slideInLeft 0.5s;
}
<!-- Slides in from left -->
/* Bounce effect -->
@keyframes bounce {
0%, 100% { transform: translateY(0); }
25% { transform: translateY(-20px); }
50% { transform: translateY(0); }
75% { transform: translateY(-10px); }
}
.ball {
animation: bounce 1s infinite;
}
<!-- Ball bounces up and down -->
/* Loading pulse -->
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.loader {
animation: pulse 1s infinite;
}
<!-- Pulsing loader effect -->
/* Rotating spinner -->
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.spinner {
animation: spin 1s linear infinite;
}
<!-- Continuous rotation -->Advanced keyframe techniques
CSS
<!-- Scale up entrance -->
@keyframes zoomIn {
0% {
opacity: 0;
transform: scale(0.5);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.element {
animation: zoomIn 0.5s ease-out;
}
<!-- Scales up while fading -->
/* Sequence animations: multiple at once -->
@keyframes enter {
0% {
opacity: 0;
transform: translateY(20px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes delayed {
0% { opacity: 0; transform: translateX(-30px); }
100% { opacity: 1; transform: translateX(0); }
}
.item:nth-child(1) { animation: enter 0.5s; }
.item:nth-child(2) { animation: enter 0.5s 0.1s backwards; }
.item:nth-child(3) { animation: enter 0.5s 0.2s backwards; }
<!-- Staggered entrance -->
/* Keyframes with easing applied per-keyframe -->
@keyframes custom-ease {
0% {
transform: translateX(0);
animation-timing-function: ease-in;
}
50% {
transform: translateX(100px);
animation-timing-function: ease-out;
}
100% {
transform: translateX(0);
}
}
<!-- Different easing between keyframes -->
/* Complex chained animation -->
@keyframes slide-flip-fade {
0% {
transform: translateX(-100px);
opacity: 0;
}
50% {
transform: translateX(0) rotateY(0deg);
opacity: 1;
}
75% {
transform: translateX(50px) rotateY(180deg);
}
100% {
transform: translateX(50px);
opacity: 0;
}
}
<!-- Combines translate, rotate, fade -->Naming and organizing animations
CSS
<!-- Semantic animation names -->
@keyframes fadeIn { /* clear: fade in */ }
@keyframes slideUp { /* clear: slide up */ }
@keyframes spin { /* clear: rotating spin */ }
@keyframes bounce { /* clear: bouncy effect */ }
<!-- Descriptive names make intent obvious -->
/* Naming convention: verb + direction -->
@keyframes slideInLeft { /* slides in from left */ }
@keyframes slideOutRight { /* slides out to right */ }
@keyframes fadeInUp { /* fades while moving up */ }
@keyframes zoomInCenter { /* zooms from center */ }
<!-- Consistent, searchable naming -->
/* Group animations by category -->
/* Entrance animations */
@keyframes fadeIn { }
@keyframes slideInLeft { }
@keyframes zoomIn { }
/* Exit animations */
@keyframes fadeOut { }
@keyframes slideOutRight { }
@keyframes zoomOut { }
/* Continuous animations */
@keyframes spin { }
@keyframes pulse { }
@keyframes bounce { }
<!-- Organized by type -->
/* Reusable animation library -->
/* Could be in separate CSS file */
@keyframes fadeIn { /* ... */ }
@keyframes slideUp { /* ... */ }
@keyframes pulse { /* ... */ }
/* Use across project */
.modal { animation: fadeIn 0.3s; }
.alert { animation: slideUp 0.5s; }
.loader { animation: pulse 1s infinite; }
<!-- Consistent animations throughout -->Note
`@keyframes` defines animation sequences using percentages (0%, 50%, 100%) or keywords (from, to). Properties transition smoothly between keyframe states. Use `animation-timing-function` to control easing. Named animations are reusable across elements. Keyframes with 0% and 100% states that match work well with `infinite` animations.
Next
Animation properties: [animation name & duration](/css/animation-name).