CSS animations and transitions bring life to web interfaces. When done correctly, they enhance user experience, provide feedback, and guide user attention. This guide covers advanced techniques for creating smooth, performant animations.
CSS Transitions
Transitions animate property changes smoothly over time.
Basic Transition
.button {
background-color: #28C55E;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #22a04a;
}
/* Multiple properties */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
Transition Timing Functions
ease: Slow start, fast middle, slow end (default)linear: Constant speedease-in: Slow startease-out: Slow endease-in-out: Slow start and endcubic-bezier(): Custom timing function
CSS Animations
Keyframe Animations
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.element {
animation: fadeIn 0.5s ease-out;
}
/* Multiple keyframes */
@keyframes slideAndFade {
0% {
opacity: 0;
transform: translateX(-100%);
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
transform: translateX(0);
}
}
Animation Properties
.animated {
animation-name: fadeIn;
animation-duration: 0.5s;
animation-timing-function: ease-out;
animation-delay: 0.2s;
animation-iteration-count: 1; /* or infinite */
animation-direction: normal; /* or reverse, alternate */
animation-fill-mode: forwards; /* or backwards, both */
animation-play-state: running; /* or paused */
}
/* Shorthand */
.animated {
animation: fadeIn 0.5s ease-out 0.2s 1 forwards;
}
Transform Properties
Transforms are GPU-accelerated and perform better than position changes:
/* Translate (move) */
.element {
transform: translateX(50px);
transform: translateY(-20px);
transform: translate(50px, -20px);
}
/* Scale */
.element {
transform: scale(1.2);
transform: scaleX(1.5);
transform: scale(1.2, 1.5);
}
/* Rotate */
.element {
transform: rotate(45deg);
transform: rotateZ(90deg);
}
/* Skew */
.element {
transform: skewX(10deg);
transform: skew(10deg, 5deg);
}
/* Multiple transforms */
.element {
transform: translateX(50px) rotate(45deg) scale(1.2);
}
Performance Optimization
Use Transform and Opacity
These properties are GPU-accelerated and don't trigger layout or paint:
/* ✅ GOOD - GPU accelerated */
.element {
transform: translateX(100px);
opacity: 0.5;
}
/* ❌ BAD - Triggers layout */
.element {
left: 100px;
width: 200px;
}
will-change Property
/* Hint browser about upcoming changes */
.animated-element {
will-change: transform, opacity;
}
/* Remove after animation */
.animated-element.animation-complete {
will-change: auto;
}
contain Property
/* Isolate animation from rest of page */
.animated-container {
contain: layout style paint;
}
Advanced Animation Patterns
Staggered Animations
.item {
animation: fadeIn 0.5s ease-out forwards;
opacity: 0;
}
.item:nth-child(1) { animation-delay: 0.1s; }
.item:nth-child(2) { animation-delay: 0.2s; }
.item:nth-child(3) { animation-delay: 0.3s; }
.item:nth-child(4) { animation-delay: 0.4s; }
/* Or with CSS custom properties */
.item {
--delay: calc(var(--index) * 0.1s);
animation-delay: var(--delay);
}
Loading Animations
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite;
}
/* Pulse animation */
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.pulse {
animation: pulse 2s ease-in-out infinite;
}
Scroll-Triggered Animations
/* Using Intersection Observer API */
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate');
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.animate-on-scroll').forEach(el => {
observer.observe(el);
});
/* CSS */
.animate-on-scroll {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.animate-on-scroll.animate {
opacity: 1;
transform: translateY(0);
}
Modern CSS Animation Features
CSS Custom Properties in Animations
.element {
--rotation: 0deg;
transform: rotate(var(--rotation));
transition: --rotation 0.3s ease;
}
.element:hover {
--rotation: 180deg;
}
Animation Composition
/* Combine multiple animations */
.element {
animation:
fadeIn 0.5s ease-out,
slideIn 0.5s ease-out,
scaleIn 0.5s ease-out;
}
Accessibility Considerations
- Respect
prefers-reduced-motionmedia query - Provide alternative ways to access animated content
- Avoid animations that can trigger motion sickness
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Real-World Example
Smooth page transitions and micro-interactions:
- Page transitions with fade and slide
- Button hover effects with scale and shadow
- Loading states with skeleton screens
- Form validation feedback animations
- Result: 40% improvement in perceived performance
Best Practices
- Keep animations subtle and purposeful
- Use transform and opacity for performance
- Respect user preferences (reduced motion)
- Test on lower-end devices
- Use appropriate durations (200-500ms for UI, longer for page transitions)
- Avoid animating layout properties
- Use easing functions for natural motion
Conclusion
CSS animations and transitions are powerful tools for enhancing user experience. Use them thoughtfully to provide feedback, guide attention, and create delightful interactions. Focus on performance by using GPU-accelerated properties, and always respect user preferences for accessibility.