Chaining Animations
Sequence multiple animations one after another using delays, events, and creative keyframe techniques.
Chaining Animations
Sometimes you need animations to play in sequence — one starting after another finishes. CSS doesn't have a built-in "play after previous" feature, but there are effective techniques to chain animations.
Technique 1: Using animation-delay
The simplest approach — offset each animation's start time:
@keyframes fadeSlideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.title {
animation: fadeSlideUp 0.5s ease both;
animation-delay: 0s;
}
.subtitle {
animation: fadeSlideUp 0.5s ease both;
animation-delay: 0.3s; /* Starts after title is partway done */
}
.button {
animation: fadeSlideUp 0.5s ease both;
animation-delay: 0.6s; /* Starts after subtitle */
}
Calculating Delays
For a true chain (each starting when the previous ends):
/* Animation A: duration 0.5s, delay 0s → ends at 0.5s */
/* Animation B: duration 0.4s, delay 0.5s → ends at 0.9s */
/* Animation C: duration 0.3s, delay 0.9s → ends at 1.2s */
.step-1 { animation: slideIn 0.5s ease both; }
.step-2 { animation: fadeIn 0.4s ease 0.5s both; }
.step-3 { animation: popIn 0.3s ease 0.9s both; }
Technique 2: Staggering with nth-child
.list-item {
animation: fadeSlideUp 0.4s ease both;
}
.list-item:nth-child(1) { animation-delay: 0.0s; }
.list-item:nth-child(2) { animation-delay: 0.1s; }
.list-item:nth-child(3) { animation-delay: 0.1s; }
.list-item:nth-child(4) { animation-delay: 0.15s; }
.list-item:nth-child(5) { animation-delay: 0.2s; }
Technique 3: CSS Custom Properties for Dynamic Stagger
.card {
opacity: 0;
animation: fadeSlideUp 0.5s ease both;
animation-delay: calc(var(--i, 0) * 0.12s);
}
<div class="card" style="--i: 0">Card 1</div>
<div class="card" style="--i: 1">Card 2</div>
<div class="card" style="--i: 2">Card 3</div>
<div class="card" style="--i: 3">Card 4</div>
Each card calculates its own delay based on its index.
Technique 4: Single @keyframes with Percentage Stages
For coordinating multiple effects on the same element:
@keyframes heroEntrance {
0% {
opacity: 0;
transform: translateY(40px) scale(0.9);
}
40% {
opacity: 1;
transform: translateY(0) scale(0.9);
}
70% {
transform: translateY(0) scale(1.02);
}
100% {
transform: translateY(0) scale(1);
}
}
.hero {
animation: heroEntrance 0.8s ease both;
}
This creates a sequence: fade+slide → elastic pop → settle. All within one set of keyframes.
Technique 5: Multiple Animations on One Element
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { transform: translateY(30px); } to { transform: translateY(0); } }
@keyframes glow { from { box-shadow: 0 0 0 transparent; } to { box-shadow: 0 0 20px #3498db; } }
.element {
animation: fadeIn 0.4s ease both,
slideUp 0.4s ease both,
glow 0.3s ease 0.4s both; /* glow starts after fade+slide */
}
Complete Example: Page Load Sequence
/* All using the same keyframe but staggered */
.header { animation: fadeSlideUp 0.5s ease both; animation-delay: 0s; }
.hero { animation: fadeSlideUp 0.6s ease both; animation-delay: 0.2s; }
.card-1 { animation: fadeSlideUp 0.4s ease both; animation-delay: 0.5s; }
.card-2 { animation: fadeSlideUp 0.4s ease both; animation-delay: 0.6s; }
.card-3 { animation: fadeSlideUp 0.4s ease both; animation-delay: 0.7s; }
.footer { animation: fadeSlideUp 0.4s ease both; animation-delay: 0.9s; }
Key Takeaways
- Chain animations using
animation-delaycalculated from previous durations - Use
nth-childfor staggered list/grid entrance animations - CSS custom properties (
--i) enable dynamic delay calculation - Multi-stage effects on one element work best with percentage-based keyframes
- Multiple comma-separated animations run simultaneously — use delay to sequence them