I’ve gathered 11 standard animations that “cover most of what you need” in web development, with live demos plus copy-paste code. The usage is the same for all of them: copy the CSS and add a class to the element you want to move.
Web animationWhat is web animation?Want to understand it from how it works? Head to the Web Animation course. This article is a toolbox for the “just use it” crowd.Appearing: when things show up on the page
Fades in softly (fade-in)
The moment the page opens, a heading or card floats up softly from below. A classic for the first view.
.fade-in {
animation: fade-in 0.8s ease both;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}For the HTML, just add the class to the element you want to reveal, like <div class="fade-in">. Change 0.8s to adjust the speed.
Appears on scroll
Only the elements that enter the screen as you scroll reveal one after another. This uses a little bit of JavaScript.
.reveal {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.is-visible {
opacity: 1;
transform: translateY(0);
}const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) entry.target.classList.add("is-visible");
});
});
document.querySelectorAll(".reveal").forEach((el) => observer.observe(el));Just add class="reveal" to the element you want to reveal and you’re set.
Hover: when the mouse is over it
The card floats up softly
For link cards and product cards. It instantly gives a “you can press this” feel.
.lift {
transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.lift:hover {
transform: translateY(-6px);
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.15);
}The button grows on hover
For the primary button. Pairing it with an :active that sinks a little on press adds a sense of response.
.grow {
transition: transform 0.2s ease;
}
.grow:hover { transform: scale(1.06); }
.grow:active { transform: scale(0.97); }The link’s underline slides out
A navigation classic. The underline runs from left to right.
.underline { position: relative; text-decoration: none; padding-bottom: 4px; }
.underline::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 2px;
background: #e5967a;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.3s ease;
}
.underline:hover::after { transform: scaleX(1); }Drawing attention: when you want to gather the eye
Bounces with a spring
For a “NEW” badge or a notification icon. It bounces repeatedly to draw the eye.
.bounce {
display: inline-block;
animation: bounce 1s ease infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
40% { transform: translateY(-12px); }
}Shakes side to side
As a signal for “your input is wrong.” When there’s an error, shaking it just once is the standard.
.shake {
animation: shake 0.4s ease;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-6px); }
75% { transform: translateX(6px); }
}In real use, you trigger it by running classList.add("shake") in JavaScript the moment an error occurs.
Floats gently
For a mascot or an illustration. It moves slowly up and down, and brings the page to life.
.float {
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-14px); }
}Loading: signaling a wait
The classic spinner
The loading classic. The HTML is a single empty <div>.
.spinner {
width: 40px;
height: 40px;
border: 4px solid #eee;
border-top-color: #e5967a;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}Dot loading
To express “thinking…”. Three dots sink in turn.
.dots { display: flex; gap: 8px; }
.dots span {
width: 12px;
height: 12px;
background: #e5967a;
border-radius: 50%;
animation: dip 1s ease-in-out infinite;
}
.dots span:nth-child(2) { animation-delay: 0.15s; }
.dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes dip {
0%, 60%, 100% { transform: translateY(0); }
30% { transform: translateY(6px); }
}Slow blink
For an “enter here” cursor or a standby display. It fades out smoothly and fades back smoothly.
.blink {
animation: blink 1.4s ease-in-out infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0.25; }
}Tips for adjusting after you copy-paste
- For speed, change the seconds like
0.8s. If unsure, 0.5–0.8s for appearing and 0.2–0.3s for hover feel comfortable - For the distance moved, change the number in
translateY(20px). Bigger is flashier, smaller is more refined - For the easing,
easeis the default. For repeating motion (bouncing, floating),ease-in-outremoves the harsh corners; keep constant rotation like a spinner aslinear - Keep always-moving things (bouncing, floating, blinking) to one or two per page. The more you add, the more your eyes scatter and nothing stands out
Summary
- Fade-in for appearing, lift / grow / underline for hover, spinner for wait time: these standards alone bring a page to life
- Once you copy-paste, adjusting just the two things, seconds and distance, makes it fit your page
- Keep always-moving things to one or two. Motion works better the more you narrow it to “the key moment”
Copy one motion you like and try it on the primary button of your own page.