SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/bounce-animations

7 CSS Bounce Animations

5 Pure CSS2 with JSPublished 2026-10-05Free · no sign-up

Seven bounces: a ball that squashes on landing, a chevron hinting at more content, a cart badge that bounces when an item is added, a card that drops in with a bounce, letters that hop in turn, a button with a springy release and icons that hop when their row is hovered.

01. Bouncing Ball with Squash

BouncePhysics

A ball that falls, squashes on impact and stretches as it leaves the ground, the first rule of animation applied in CSS. The fall uses ease-in and the rise ease-out, set per keyframe with animation-timing-function, so it accelerates like real gravity.

View code
<div class="bn1" aria-hidden="true"><span class="ball"></span><span class="floor"></span></div>
.bn1 { position: relative; width: 140px; height: 190px; }
.bn1 .ball { position: absolute; left: 45px; top: 0; width: 50px; height: 50px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #fecaca, #ef4444 50%, #991b1b); animation: bn1 1s infinite; }
.bn1 .floor { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; border-radius: 2px; background: #d0d5dd; }
@keyframes bn1 { 0% { transform: translateY(0) scale(.95, 1.05); animation-timing-function: ease-in; } 45% { transform: translateY(137px) scale(.95, 1.08); } 50% { transform: translateY(140px) scale(1.25, .75); animation-timing-function: ease-out; } 55% { transform: translateY(130px) scale(.95, 1.08); } 100% { transform: translateY(0) scale(.95, 1.05); } }
@media (prefers-reduced-motion: reduce) { .bn1 .ball { animation: none; transform: translateY(140px); } }

02. Scroll Down Hint

BounceHint

A chevron at the bottom of a hero bounces gently to suggest there is more below. It is a link to the next section with a visible text label, so it also works as a skip link, and the bounce stops for reduced motion.

View code
<a class="bn2" href="#features"><span>Scroll</span><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg></a>
.bn2 { display: grid; justify-items: center; gap: 4px; color: #cbd5e1; font: 600 12px Inter, system-ui, sans-serif; letter-spacing: .14em; text-transform: uppercase; text-decoration: none; }
.bn2 svg { width: 30px; height: 30px; fill: none; stroke: #f8fafc; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; animation: bn2 1.8s cubic-bezier(.5,0,.5,1) infinite; }
@keyframes bn2 { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(8px); } }
.bn2:focus-visible { outline: 2px solid #93c5fd; outline-offset: 4px; border-radius: 6px; }
@media (prefers-reduced-motion: reduce) { .bn2 svg { animation: none; } }

03. Cart Badge Bounce on Add

BounceEcommerce

Adding an item bumps the cart count and the badge bounces, confirming the action where the eye is not looking. The count is part of the cart link's accessible name, and a polite live region says Added to cart for screen reader users.

View code
<div class="bn3"><a href="#cart" class="cart" aria-label="Cart, 2 items"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5h2l2 10h10l2-7H7"/><circle cx="10" cy="19" r="1.5"/><circle cx="17" cy="19" r="1.5"/></svg><span class="n" aria-hidden="true">2</span></a><button>Add to cart</button><p class="sr" aria-live="polite"></p></div>
.bn3 { display: flex; align-items: center; gap: 18px; font-family: Inter, system-ui, sans-serif; }
.bn3 .cart { position: relative; display: grid; place-items: center; width: 48px; height: 48px; border-radius: 12px; background: #f2f4f7; }
.bn3 svg { width: 26px; height: 26px; fill: none; stroke: #101828; stroke-width: 1.8; stroke-linejoin: round; }
.bn3 .n { position: absolute; top: -4px; right: -4px; display: grid; place-items: center; min-width: 20px; height: 20px; border-radius: 10px; background: #7f56d9; color: #fff; font-size: 11px; font-weight: 800; }
.bn3 .n.pop { animation: bn3 .5s cubic-bezier(.3,1.6,.6,1); }
@keyframes bn3 { 0% { transform: scale(1); } 40% { transform: scale(1.5) translateY(-4px); } 100% { transform: scale(1); } }
.bn3 button { padding: 11px 18px; border: 0; border-radius: 10px; background: #101828; color: #fff; font: 700 14px Inter, system-ui, sans-serif; cursor: pointer; }
.bn3 :focus-visible { outline: 3px solid #84adff; outline-offset: 2px; }
.bn3 .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
@media (prefers-reduced-motion: reduce) { .bn3 .n.pop { animation: none; } }
var n = document.querySelector('.bn3 .n'), cart = document.querySelector('.bn3 .cart'), live = document.querySelector('.bn3 .sr'), k = 2;
document.querySelector('.bn3 button').onclick = function () { k++; n.textContent = k; cart.setAttribute('aria-label', 'Cart, ' + k + ' items'); live.textContent = 'Added to cart. ' + k + ' items.'; n.classList.remove('pop'); void n.offsetWidth; n.classList.add('pop'); };

04. Bounce-In Entrance

BounceEntrance

A success card drops in with a bounce, overshooting slightly and settling, made with three keyframes rather than a library. The card's message is in a role="status" region so its appearance is announced, whatever the animation does.

View code
<div class="bn4"><div class="card" role="status"><b>Payment received</b><span>Receipt sent to your email.</span></div><button>Replay</button></div>
.bn4 { display: grid; justify-items: center; gap: 12px; font-family: Inter, system-ui, sans-serif; }
.bn4 .card { display: grid; gap: 2px; padding: 16px 20px; border-radius: 14px; background: #052e16; border: 1px solid #166534; color: #bbf7d0; font-size: 14px; animation: bn4 .8s both; }
.bn4 b { color: #fff; font-size: 16px; }
@keyframes bn4 { 0% { opacity: 0; transform: translateY(-40px) scale(.9); } 60% { opacity: 1; transform: translateY(8px) scale(1.02); } 80% { transform: translateY(-3px); } 100% { transform: none; } }
.bn4 button { padding: 6px 12px; border: 1px solid #334155; border-radius: 6px; background: transparent; color: #cbd5e1; font: 600 12px Inter, system-ui, sans-serif; cursor: pointer; }
.bn4 button:focus-visible { outline: 2px solid #86efac; outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .bn4 .card { animation: none; } }
var c = document.querySelector('.bn4 .card');
document.querySelector('.bn4 button').onclick = function () { c.style.animation = 'none'; void c.offsetWidth; c.style.animation = ''; };

05. Bouncing Letters

BounceText

The letters of a short word hop one after another and land with a squash, a cheerful touch for a kids brand or a 404 page. Letters are aria-hidden spans and the word is repeated as visually hidden text so it is read normally.

View code
<p class="bn5"><span class="sr">Hooray</span><span aria-hidden="true"><i style="--i:0">H</i><i style="--i:1">o</i><i style="--i:2">o</i><i style="--i:3">r</i><i style="--i:4">a</i><i style="--i:5">y</i></span></p>
.bn5 { margin: 0; font: 900 50px "Comic Sans MS", "Chalkboard SE", Inter, sans-serif; color: #f97316; }
.bn5 i { display: inline-block; font-style: normal; transform-origin: bottom; animation: bn5 1.6s ease-in-out infinite; animation-delay: calc(var(--i) * 100ms); }
.bn5 i:nth-child(even) { color: #0ea5e9; }
.bn5 .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
@keyframes bn5 { 0%, 40%, 100% { transform: none; } 15% { transform: translateY(-16px); } 30% { transform: scale(1.15, .85); } }
@media (prefers-reduced-motion: reduce) { .bn5 i { animation: none; } }

06. Springy Press Feedback

BounceButton

The button squashes when pressed and springs back past its size before settling, thanks to a cubic-bezier with an overshoot value above 1 on the release transition. The press itself uses a quick ease-out so it never feels laggy.

View code
<button class="bn6">Like</button>
.bn6 { padding: 14px 30px; border: 0; border-radius: 999px; background: #f43f5e; color: #fff; font: 800 16px Inter, system-ui, sans-serif; cursor: pointer; transition: transform .45s cubic-bezier(.34,1.8,.64,1); }
.bn6:active { transform: scale(.88); transition: transform .08s ease-out; }
.bn6:focus-visible { outline: 3px solid #fda4af; outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .bn6, .bn6:active { transition: none; transform: none; } }

07. Icon Hop on Hover

BounceIcon

Icons in a feature list hop once when their row is hovered or focused, a small reward that draws attention to the row under the pointer. The hop is a short keyframe animation started by the hover state, so it plays once each time.

View code
<ul class="bn7"><li><a href="#fast"><span aria-hidden="true">⚡</span>Fast setup</a></li><li><a href="#secure"><span aria-hidden="true">🔒</span>Secure by default</a></li><li><a href="#support"><span aria-hidden="true">💬</span>Real support</a></li></ul>
.bn7 { display: grid; gap: 8px; width: 240px; max-width: 100%; margin: 0; padding: 0; list-style: none; font-family: Inter, system-ui, sans-serif; }
.bn7 a { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; color: #101828; font-weight: 600; text-decoration: none; }
.bn7 span { display: inline-block; font-size: 20px; }
.bn7 a:hover span, .bn7 a:focus-visible span { animation: bn7 .5s ease; }
@keyframes bn7 { 30% { transform: translateY(-8px); } 60% { transform: translateY(0) scale(1.1, .9); } 80% { transform: translateY(-2px); } }
.bn7 a:focus-visible { outline: 3px solid #84adff; outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .bn7 a:hover span, .bn7 a:focus-visible span { animation: none; } }

About these CSS Bounce Animations

Gravity is easing

A bounce looks real when the fall speeds up and the rise slows down. Set animation-timing-function: ease-in on the falling keyframe and ease-out on the rising one; the timing function applies until the next keyframe.

Squash and stretch

Scale an object wider and shorter at the moment of impact and taller and thinner in flight. Keep its volume roughly constant, so 1.25 by 0.75 rather than 1.25 by 1.

Overshoot with cubic-bezier

A cubic-bezier() whose second or fourth value is above 1 overshoots its target before settling, which gives a spring without extra keyframes.

Bounce for feedback

A badge that bounces when its number changes confirms an action out of the corner of the eye. Pair it with a live region so the change is also announced.

Frequently asked questions

How do I replay a bounce?

Remove the animation, force a reflow by reading offsetWidth, and set it again, as the demos with Replay buttons do.

Are infinite bounces annoying?

Often. Keep looping bounces for small hints and stop them on reduced motion.

Do I need a physics library?

Not for these. Keyframes with easing cover most interface bounces.