Web Animations Guide
CSS Animations
/* Define keyframes */
@keyframes slideIn {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
/* Apply animation */
.modal {
animation: slideIn 300ms ease-out both;
}
.badge {
animation: pulse 2s ease-in-out infinite;
}
/* animation shorthand: name duration timing-function delay iteration direction fill-mode */
.card:hover {
animation: pulse 400ms ease-in-out 0s 1 normal forwards;
}
/* Multiple animations */
.element {
animation: slideIn 0.3s ease, pulse 2s 0.3s infinite;
}
Web Animations API (WAAPI)
// Basic animation
const el = document.querySelector('.box');
const animation = el.animate([
{ transform: 'translateX(0)', opacity: 1 },
{ transform: 'translateX(200px)', opacity: 0.5 },
{ transform: 'translateX(400px)', opacity: 0 }
], {
duration: 1000, // ms
easing: 'ease-in-out',
delay: 0,
fill: 'forwards', // persist end state
iterations: 1, // Infinity for looping
direction: 'alternate'
});
// Control playback
animation.pause();
animation.play();
animation.reverse();
animation.cancel();
animation.finish();
// Events
animation.finished.then(() => console.log('Done!'));
animation.onfinish = () => el.remove();
Animation Timing Functions
| Function | Description | Feel |
|---|---|---|
| linear | Constant speed | Mechanical |
| ease | Slow start, fast middle, slow end | Natural (default) |
| ease-in | Starts slow | Objects leaving |
| ease-out | Ends slow | Objects entering |
| ease-in-out | Both slow | Objects passing through |
| cubic-bezier() | Custom curve | Any feel |
| spring() | Physics-based spring | Bouncy, natural |
Performance Best Practices
/* Only animate GPU-composited properties */
/* GOOD — no layout/paint triggered */
.anim {
transform: translateX(100px) scale(1.1) rotate(45deg);
opacity: 0.5;
filter: blur(4px);
}
/* BAD — triggers layout */
.bad-anim {
top: 100px; /* layout */
left: 100px; /* layout */
width: 200px; /* layout */
margin: 10px; /* layout */
}
/* Hint browser to prepare compositing layer */
.will-animate {
will-change: transform, opacity;
}
/* Remove after animation to free memory */
element.addEventListener('animationend', () => {
element.style.willChange = 'auto';
});