Web animations can be implemented using either CSS or JavaScript, with the optimal choice depending on the complexity of the effect and the level of control required.
Quick Guidelines
- Prefer CSS animations for simple, declarative transitions like toggling UI states.
- Use JavaScript when you need fine-grained control—such as pausing, reversing, or dynamically adjusting timing.
- For JavaScript-based animation, consider the Web Animations API or established libraries like GSAP.
Both approaches can achieve similar visual results, but differ in maintainability, performance characteristics, and flexibility.
- CSS is ideal for self-contained state changes (e.g., sliding in a sidebar or fading a tooltip). JavaScript can toggle CSS classes to trigger these animations while letting the browser handle rendering.
- JavaScript excels when orchestrating complex sequences, especially in interactive applications or games. The Web Animations API offers a standardized way too animate CSS properties with scriptable control.
- For maximum performance in canvas-based or game-like scenarios, use
requestAnimationFramedirectly.
If your project already relies on a library like jQuery ($.animate()) or GreenSock (GSAP), sticking with it may streamline development.
Implementing Animations with CSS
CSS animations are declarative: you define the start and end states (or keyframes), and the browser interpolates between them.
For example, moving an element 100px right and down over 500ms:
.box {
transform: translate(0, 0);
transition: transform 500ms;
}
.box.move {
transform: translate(100px, 100px);
}
Toggle the animation via JavaScript by adding the class:
element.classList.add('move');
This separation keeps logic (JS) and presentation (CSS) distinct. To detect when the transition ends, listen for the transitionend event (supported since IE10):
const el = document.querySelector('.box');
el.addEventListener('transitionend', () => {
// Animation complete
});
For more complex sequences, use @keyframes to define multi-step animations:
.animated-box {
animation-name: drift;
animation-duration: 1300ms;
animation-iteration-count: infinite;
animation-direction: alternate;
}
@keyframes drift {
0% { transform: translate(0, 0); opacity: 0.3; }
25% { opacity: 0.9; }
50% { transform: translate(100px, 100px); opacity: 0.2; }
100% { transform: translate(30px, 30px); opacity: 0.8; }
}
Note that vendor prefixes (e.g., -webkit-) may still be needed for older Safari and Android browsers, though modern tools can auto-generate them.
Animating with JavaScript and the Web Animations API
JavaScript animations are imperative, offering runtime control over every frame. The Web Animations API provides a native interface too animate CSS properties:
const target = document.querySelector('.box');
const anim = target.animate([
{ transform: 'translate(0, 0)' },
{ transform: 'translate(100px, 100px)' }
], {
duration: 500,
fill: 'forwards'
});
anim.addEventListener('finish', () => {
target.style.transform = 'translate(100px, 100px)';
});
By default, Web Animations affect only the compositor layer. To persist the final state, update the element’s inline style or use fill: 'forwards'.
This API is natively supported in Chrome, Edge, and Opera, with polyfills available for broader compatibility. It enables dynamic manipulation—pausing, reversing, or adjusting playback rate—which is invaluable for interactive experiences or object-oriented UI architectures.