Animations & Transitions
Create smooth, performant animations with CSS transitions and keyframes
CSS Transitions
Transitions interpolate between states when a property changes.
.button {
background: #6366f1;
transform: scale(1);
transition:
background 0.3s ease,
transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.button:hover {
background: #4f46e5;
transform: scale(1.05);
}
Shorthand: transition: property duration easing delay;
display: none -> block won't transition. Use opacity + visibility for fade effects.@keyframes
Define multi-step animations with named keyframes.
@keyframes slide-in {
from {
opacity: 0;
transform: translateX(-100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes bounce {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
.animated-card {
animation:
slide-in 0.5s ease-out,
bounce 2s infinite 0.5s;
}
Animation Properties
| Property | Purpose | Example |
|---|---|---|
animation-name | Which @keyframes to use | slide-in |
animation-duration | Length of one cycle | 0.5s |
animation-timing-function | Easing curve | ease-in-out |
animation-iteration-count | How many cycles | infinite |
animation-direction | Play forward, reverse, alternate | alternate |
animation-delay | Wait before starting | 0.2s |
animation-fill-mode | State before/after animation | forwards |
.spinner {
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
Easing Functions
/* CSS named easings */
transition: transform 0.3s ease-in-out;
/* cubic-bezier(x1, y1, x2, y2) for custom curves */
transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55);
/* steps(N) for discrete, frame-by-frame animation */
animation: typewriter 2s steps(10) forwards;
Transform & will-change
transform animates on the GPU (composite layer). will-change hints the browser.
.card {
will-change: transform, opacity;
transition:
transform 0.3s,
opacity 0.3s;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
opacity: 0.9;
}
Overuse creates memory pressure. Apply it right before animation starts, remove after. Or let the browser optimize on its own for simple transforms.
Accessibility: prefers-reduced-motion
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
See It In Action
Try creating a custom animation with CSS keyframes:
1@keyframes bounce {20%, 100% { transform: translateY(0); }350% { transform: translateY(-20px); }4}5.pulse-box {6background: #6366f1;7color: white;8padding: 1.5rem 2rem;9border-radius: 8px;10cursor: pointer;11animation: bounce 0.6s ease infinite;12}A `@keyframes bounce` rule defines a vertical bounce effect. Setting `animation: bounce 0.6s ease infinite` makes the element loop continuously. The animation applies to the `.pulse-box` selector, animating `translateY` between 0 and -20px.
1<div class="container">2<div class="spinner"></div>3<div class="reveal-card">4 <h3>Content Loaded</h3>5 <p>This card should slide in after loading.</p>6</div>7</div>Combines a CSS border-spinner with a card that slides in on load. The `.spinner` rotates via a `border-top-color` trick, while the `.reveal-card` demonstrates an entrance animation triggered after content is ready.