CSS animations are powerful, but they don't know when to start. An animation that starts immediately when the page loads is wasted if the element isn't visible yet. This demo compares different approaches to triggering animations at the right time.
These cards animate immediately on page load, even though you can't see them yet. By the time you scroll here, the animation has already finished!
This animation started as soon as the page loaded, wasting the effect.
You probably missed this animation entirely because it finished before you scrolled here.
Without triggers, animations happen at the wrong time and don't enhance UX.
/* β This starts immediately - bad UX */
.feature-card {
opacity: 0;
animation: fadeInUp 0.8s ease-out forwards;
}
/* Animation runs even when element is off-screen */
These cards use Intersection Observer to animate only when they enter the viewport. Scroll down to see them animate at the perfect moment! (They'll glow green while being observed)
This animates exactly when it becomes visible, creating the best user experience.
Intersection Observer is efficient and doesn't block the main thread.
Notice how cards animate in sequence for a polished, professional feel.
/* β
Cards start invisible */
.feature-card {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
}
/* JS adds this class when visible */
.feature-card.animate-in {
opacity: 1;
transform: translateY(0);
}
// β
Intersection Observer setup
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const delay = entry.target.dataset.delay || 0;
setTimeout(() => {
entry.target.classList.add('animate-in');
}, delay);
observer.unobserve(entry.target); // Stop observing after animation
}
});
}, { threshold: 0.2 }); // Trigger when 20% visible
document.querySelectorAll('.observe-me').forEach(card => {
observer.observe(card);
});
Works perfectly on touch devices without draining battery.
Respects prefers-reduced-motion and provides instant fallbacks.
Adjust thresholds, delays, and root margins easily.
Notice in the stats at the top: Intersection callbacks fire only when needed, while scroll events fire constantly. This demo tracks both to show the dramatic difference.