25 CSS Text Animations 12 / 25
CSS Bouncing Letters Animation
Individual letters bounce with elastic spring physics using cubic-bezier overshoot easing and staggered delays for a playful, energetic effect.
The code
<div class="ta-12">
<div class="ta-12__stage">
<div class="ta-12__text">
<span style="--i:0">B</span><span style="--i:1">O</span><span style="--i:2">U</span><span
style="--i:3">N</span><span style="--i:4">C</span><span style="--i:5">E</span>
<span style="--i:6"> </span>
<span style="--i:7">!</span>
</div>
</div>
</div> <div class="ta-12">
<div class="ta-12__stage">
<div class="ta-12__text">
<span style="--i:0">B</span><span style="--i:1">O</span><span style="--i:2">U</span><span
style="--i:3">N</span><span style="--i:4">C</span><span style="--i:5">E</span>
<span style="--i:6"> </span>
<span style="--i:7">!</span>
</div>
</div>
</div>.ta-12, .ta-12 *, .ta-12 *::before, .ta-12 *::after {
margin: 0; padding: 0; box-sizing: border-box;
}
.ta-12 ::selection { background: #f59e0b; color: #fff; }
.ta-12 {
--bg: linear-gradient(160deg, #1a0a2e, #0d1117);
min-height: 100vh;
background: var(--bg);
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
font-family: 'Syne', 'Helvetica Neue', sans-serif;
}
.ta-12__stage { text-align: center; }
.ta-12__text {
font-size: clamp(3rem, 9vw, 5.5rem);
font-weight: 900;
letter-spacing: 0.05em;
display: flex;
justify-content: center;
}
.ta-12__text span {
display: inline-block;
color: #fbbf24;
animation: ta-12-bounce 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) infinite alternate;
animation-delay: calc(var(--i) * 0.09s);
text-shadow: 0 6px 20px rgba(251, 191, 36, 0.4);
}
.ta-12__text span:nth-child(even) { color: #f43f5e; text-shadow: 0 6px 20px rgba(244, 63, 94, 0.4); }
@keyframes ta-12-bounce {
0% {
transform: translateY(0) scaleX(1) scaleY(1);
}
60% {
transform: translateY(-28px) scaleX(0.9) scaleY(1.1);
}
80% {
transform: translateY(-22px) scaleX(0.95) scaleY(1.05);
}
100% {
transform: translateY(-28px) scaleX(0.9) scaleY(1.1);
}
}
@media (prefers-reduced-motion: reduce) {
.ta-12__text span { animation: none; transform: none; }
} .ta-12, .ta-12 *, .ta-12 *::before, .ta-12 *::after {
margin: 0; padding: 0; box-sizing: border-box;
}
.ta-12 ::selection { background: #f59e0b; color: #fff; }
.ta-12 {
--bg: linear-gradient(160deg, #1a0a2e, #0d1117);
min-height: 100vh;
background: var(--bg);
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
font-family: 'Syne', 'Helvetica Neue', sans-serif;
}
.ta-12__stage { text-align: center; }
.ta-12__text {
font-size: clamp(3rem, 9vw, 5.5rem);
font-weight: 900;
letter-spacing: 0.05em;
display: flex;
justify-content: center;
}
.ta-12__text span {
display: inline-block;
color: #fbbf24;
animation: ta-12-bounce 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) infinite alternate;
animation-delay: calc(var(--i) * 0.09s);
text-shadow: 0 6px 20px rgba(251, 191, 36, 0.4);
}
.ta-12__text span:nth-child(even) { color: #f43f5e; text-shadow: 0 6px 20px rgba(244, 63, 94, 0.4); }
@keyframes ta-12-bounce {
0% {
transform: translateY(0) scaleX(1) scaleY(1);
}
60% {
transform: translateY(-28px) scaleX(0.9) scaleY(1.1);
}
80% {
transform: translateY(-22px) scaleX(0.95) scaleY(1.05);
}
100% {
transform: translateY(-28px) scaleX(0.9) scaleY(1.1);
}
}
@media (prefers-reduced-motion: reduce) {
.ta-12__text span { animation: none; transform: none; }
}How this works
Each letter is a display: inline-block span so transform applies individually. The ta-12-bounce keyframe uses a tall translateY drop combined with a custom cubic-bezier(0.34, 1.56, 0.64, 1) easing — a curve that overshoots its target value before settling back, simulating a rubber ball's elastic rebound without requiring JS spring physics.
The squash-and-stretch illusion is enhanced by pairing the bounce with scaleX(1.2) scaleY(0.8) at the bottom contact point and scaleX(0.9) scaleY(1.1) at the peak — these scale adjustments happen in a multi-stop keyframe. Each letter gets a cascading animation-delay via the CSS custom property --i, creating the wave-of-bouncing-balls visual.
Customize
- Increase the bounce height by changing the
translateY(-30px)peak totranslateY(-50px)for bigger air time. - Adjust the elasticity by tweaking the bezier curve — try
cubic-bezier(0.34, 2.2, 0.64, 1)for extreme overshoot like a super-ball. - Add colour change at the bounce peak by animating
colorin the keyframe to a highlight hue at the 50% mark. - Change the animation direction to bounce from top to bottom using
translateY(-30px)as the start state and animating totranslateY(0). - Apply to a logo mark or icon element alongside the text to bounce the entire layout unit together.
Watch out for
- Inline spans ignore
transform— always setdisplay: inline-blockon each letter span or the bounce has no visible effect. - The cubic-bezier overshoot (
y > 1) creates values outside the0–100%property range for non-transform properties; only use it withtransformwhere overshooting is valid. - Many simultaneously bouncing letters on mobile can drop frame rates; consider using
animation-play-state: pausedon elements outside the viewport.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 36+ | 9+ | 16+ | 36+ |
cubic-bezier with y-values outside 0–1 is supported for transforms in Chrome 54+, Firefox 65+, Safari 14+. Older browsers clip the easing curve.