Learn the basics of JavaScript animations, from CSS transitions to using powerful libraries like GSAP and Anime.js. Build interactive, dynamic web animations.
A page that snaps between states feels broken even when it works fine. Toggle a menu open instantly and people flinch. Ease it open over 200ms and the same interaction reads as intentional. That gap is what animation buys you.
Day 19 of the 30 Days of JavaScript series is about closing that gap. We’ll cover CSS transitions and animations, when to reach for a JavaScript library instead, and build a small loader you can drop into a real project. One rule up front: use the cheapest tool that does the job. CSS first, JavaScript when CSS can’t.
Table of Contents
- CSS Transitions and Animations
- JavaScript Animation Libraries
- Building a Simple Animation Project
- Advanced Animation Techniques
- Conclusion
CSS Transitions and Animations
CSS handles most of the animation you’ll ever need, and there’s a detail that matters more than any syntax: animate transform and opacity and the browser can hand the work off to the GPU, no layout recalculation per frame. Animate width, height, or top and it can’t, so it re-lays-out every frame and the motion stutters. Stick to transform and opacity and your animations stay smooth for almost free.
Understanding CSS Transitions
A transition interpolates between two states over a duration. You set the resting state, change a property later (on hover, or when you toggle a class), and the browser fills in the frames.
/**
* Simple button transition that changes background color on hover.
*/
.button {
background-color: #4CAF50;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #45a049;
}Exploring CSS Animations
Transitions go from A to B. When you need more than one step, or you want it to loop, or run on load with no interaction to trigger it, reach for @keyframes.
/**
* Keyframes example for sliding in an element from the left.
*/
@keyframes slidein {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
.slider {
animation: slidein 1s ease-in-out;
}JavaScript Animation Libraries
CSS runs out of room when animation gets coordinated: sequencing several elements, reacting to scroll position, timelines you can pause and reverse on demand. That’s where a library earns its weight. GSAP and Anime.js are the two you’ll hear about most.
GreenSock Animation Platform (GSAP)
GSAP animates CSS, SVG, and canvas, and it’s fast and consistent across browsers. Worth knowing: it’s now free for everyone, including the plugins that used to sit behind a paid membership, after Webflow took it on. So there’s no cost reason to skip it anymore.
/**
* Rotates and scales an element using GSAP.
*
* @returns {void}
*/
gsap.to(".box", { duration: 2, rotation: 360, scale: 1.5 });Anime.js
Anime.js is the lighter option for CSS properties, SVG, and DOM attributes. One caveat before you copy the snippet below: this is the v3 syntax. Anime.js v4 reworked the API to named imports like animate(), so check which version you’re pulling in before trusting an older example.
/**
* Creates a looping animation on an element using Anime.js.
*
* @returns {void}
*/
anime({
targets: '.circle',
scale: 2,
loop: true,
direction: 'alternate',
easing: 'easeInOutQuad'
});Building a Simple Animation Project
Enough concepts. Let’s build a spinning loader that hides itself once the page is ready. Three small pieces: markup, a CSS animation, and a bit of JavaScript to dismiss it.
Setting Up the HTML
Start with the structure: a container and the spinner inside it.
/**
* Loader HTML structure.
*/
<div class="loader-container">
<div class="loader"></div>
</div>Styling the Loader with CSS
The spin is pure CSS. Notice it animates transform: rotate, the cheap property, so it stays smooth even while the rest of the page is working.
/**
* Loader styling with a spinning animation.
*/
.loader {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid #3498db;
border-radius: 50%;
animation: spin 2s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}Adding Interactivity with JavaScript
Here we fake a load with setTimeout and fade the loader out. In real code you’d fire this when your data or images actually finish, not on a fixed three-second timer that’s right by luck.
/**
* Simulates a loading process and hides the loader after 3 seconds.
*
* @returns {void}
*/
document.addEventListener("DOMContentLoaded", function() {
const loader = document.querySelector('.loader-container');
setTimeout(() => {
loader.style.opacity = '0';
loader.style.visibility = 'hidden';
document.body.innerHTML += '<h1>Welcome to the Website</h1>';
}, 3000);
});Advanced Animation Techniques
Two things worth knowing once the basics click: chaining and the browser’s own animation API.
Chaining Animations
GSAP timelines let you line up animations one after another instead of juggling delays by hand.
/**
* Creates a sequence of animations using GSAP's timeline feature.
*
* @returns {void}
*/
gsap.timeline()
.to(".box", { duration: 1, x: 100 })
.to(".box", { duration: 1, y: 100 })
.to(".box", { duration: 1, scale: 2 });Using the Web Animations API
element.animate() gives you keyframe animations from JavaScript with no library at all. It returns an Animation object you can pause, reverse, or play, and it runs on the same optimized path as CSS, so you keep the performance without the dependency.
/**
* Animates an element's position using the Web Animations API.
*
* @returns {void}
*/
document.querySelector('.box').animate([
{ transform: 'translateX(0px)' },
{ transform: 'translateX(100px)' }
], {
duration: 1000,
iterations: Infinity,
easing: 'ease-in-out'
});
One thing to avoid: driving animation with setInterval. If you ever move something frame by frame in JavaScript, use requestAnimationFrame instead, and base each step on the timestamp it hands you so the motion runs at the same speed whether the screen refreshes at 60Hz or 120Hz. Most of the time CSS or element.animate() means you never write that loop yourself, which is the point.
Conclusion
That’s the full ladder: CSS transitions for simple state changes, @keyframes for loops and sequences, a library like GSAP when you’re coordinating many moving parts, and the Web Animations API when you want JavaScript control without pulling in a dependency. We also built a loader that ties markup, CSS, and JavaScript together.
Animation isn’t decoration. Motion tells people what just happened and where to look. Used with restraint it makes an interface feel considered. Overused it makes it feel busy and slow. Pick the lightest tool, animate transform and opacity where you can, and stop once the interaction reads clearly.
What’s Next?
Day 20 is Accessibility and JavaScript: building interfaces that work for everyone, including people navigating by keyboard or screen reader. It pairs closely with today, since motion and accessibility collide fast. The prefers-reduced-motion media query is the first thing to reach for when you want to respect users who ask for less animation. See you there.


