Master CSS animations and transitions — keyframes, performance optimization, scroll-driven animations, and creative techniques that make websites feel alive.
Start with transitions before diving into keyframes:
/* Smooth hover effect */
.card {
transform: translateY(0);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
transition: transform 0.3 ease box-shadow ease
/* Fade in from bottom */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-up {
animation: fadeInUp 0.6s ease-out forwards;
}
/* Stagger children */
.stagger-list > *:nth-child(1) { animation-delay: 0ms; }
.stagger-list > *:nth-child(2) { animation-delay: 100ms; }
.stagger-list > *:nth-child(3) { animation-delay: 200ms; }
.stagger-list > *:nth-child(4) { animation-delay: 300ms; }
.stagger-list > *:nth-child(5) { animation-delay: 400ms; }
The newest CSS feature — animations tied to scroll position without JavaScript:
/* Progress bar that fills as you scroll */
.scroll-progress {
position: fixed;
top: 0;
left: 0;
height: 4px;
background: linear-gradient(90deg, #6366f1, #8b5cf6);
transform-origin: left;
animation: fillProgress linear;
animation-timeline: scroll();
}
@keyframes fillProgress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* Reveal sections on scroll */
.reveal-section {
opacity: 0;
transform: translateY(50px);
animation: revealOnScroll ease-out;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
@keyframes revealOnScroll {
to {
opacity: 1;
transform: translateY(0);
}
}
With Tailwind CSS, many animations are built-in:
<!-- Spin (loading indicators) -->
<svg class="animate-spin h-5 w-5 text-indigo-600">...</svg>
<!-- Bounce (call-to-action) -->
<button class="animate-bounce">Get Started ↓</button>
<!-- Pulse (skeleton loaders) -->
<div class="animate-pulse bg-gray-200 h-4 w-48 rounded"></div>
<!-- Ping (notification badges) -->
<span class="relative flex h-3 w-3">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-3 w-3 bg-red-500"></span>
</span>
Custom Tailwind animations:
// tailwind.config.ts
export default {
theme: {
extend: {
animation: {
"fade-in-up": "fadeInUp 0.6s ease-out forwards",
"slide-in-right": "slideInRight 0.4s ease-out forwards",
"scale-in": "scaleIn 0.3s ease-out forwards",
"float": "float 3s ease-in-out infinite",
},
keyframes: {
fadeInUp: {
"0%": { opacity: "0", transform: "translateY(20px)" },
"100%": { opacity: "1", transform: "translateY(0)" },
},
slideInRight: {
"0%": { opacity: "0", transform: "translateX(20px)" },
"100%": { opacity: "1", transform: "translateX(0)" },
},
scaleIn: {
"0%": { opacity: "0", transform: "scale(0.95)" },
"100%": { opacity: "1", transform: "scale(1)" },
},
float: {
"0%, 100%": { transform: "translateY(0)" },
"50%": { transform: "translateY(-10px)" },
},
},
},
},
};
DO animate these properties (GPU-accelerated):
transform: translateX() translateY() scale() rotate();
opacity: 0 → 1;
filter: blur() brightness();
DON'T animate these properties (trigger layout):
width, height /* Trigger layout recalculation */
margin, padding /* Trigger layout recalculation */
top, left /* Use transform instead */
border-width /* Trigger layout + paint */
font-size /* Trigger layout + paint */
Use will-change wisely:
/* Only when you know animation will happen */
.card:hover {
will-change: transform;
}
/* Remove after animation */
.card {
will-change: auto;
}
.skeleton {
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e0e0e0 50%,
#f0f0f0 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
We use this pattern extensively in our Developer Portfolio Platform for loading states across all 15+ modules.
Small animations that make big differences:
/* Like button heart animation */
.like-btn {
transition: transform 0.1s ease;
}
.like-btn:active {
transform: scale(1.3);
}
.like-btn.liked {
animation: heartBeat 0.4s ease;
}
@keyframes heartBeat {
0% { transform: scale(1); }
25% { transform: scale(1.3); }
50% { transform: scale(0.9); }
100% { transform: scale(1); }
}
/* Toggle switch */
.toggle-knob {
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.toggle.active .toggle-knob {
transform: translateX(24px);
}
All our templates feature polished animations:
FadeIn and SpotlightCard componentsRelated reads:
Follow on Instagram for animation demos and UI inspiration.
Beautiful animations ship in every template. Browse our premium templates — AgencyPro, Flavex, NovaAdmin, and more.
Get the latest articles, tutorials, and updates delivered straight to your inbox. No spam, unsubscribe at any time.