20 CSS Animated Buttons 09 / 20

CSS Jelly Bounce Button Animation

Playful elastic micro-interaction buttons that wobble with a jelly-like spring on hover and snap back with an overshoot settle using CSS scale and skew keyframes.

Pure CSS MIT licensed
Live Demo Open in tab
Open in playground

The code

<div class="ab-09">
  <p class="ab-09__label">Hover for jelly effect</p>
  <div class="ab-09__row">
    <button class="ab-09__btn ab-09__btn--pink">Subscribe!</button>
    <button class="ab-09__btn ab-09__btn--lime">Let's Go!</button>
    <button class="ab-09__btn ab-09__btn--sky">Join Now!</button>
  </div>
</div>
.ab-09,.ab-09 *,.ab-09 *::before,.ab-09 *::after{box-sizing:border-box;margin:0;padding:0}
.ab-09 ::selection{background:#ec4899;color:#fff}
.ab-09{
  font-family:system-ui,sans-serif;
  background:#fdf2ff;
  min-height:100vh;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:2rem;
  padding:2rem;
}
.ab-09__label{
  font-size:.78rem;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:#a855f7;
  opacity:.6;
}
.ab-09__row{
  display:flex;
  gap:1.25rem;
  flex-wrap:wrap;
  justify-content:center;
}
.ab-09__btn{
  --c:#ec4899;
  padding:.85rem 2.2rem;
  font-size:1.05rem;
  font-weight:800;
  color:#fff;
  background:var(--c);
  border:none;
  border-radius:50px;
  cursor:pointer;
  outline:none;
  letter-spacing:.03em;
  transform-origin:center;
  box-shadow:0 4px 16px rgba(0,0,0,.15);
  will-change:transform;
}
.ab-09__btn--pink{--c:#ec4899}
.ab-09__btn--lime{--c:#16a34a}
.ab-09__btn--sky{--c:#0284c7}
.ab-09__btn:hover{animation:ab-09-jelly .7s cubic-bezier(.4,0,.2,1) both}
@keyframes ab-09-jelly{
  0%{transform:scale(1)}
  10%{transform:scaleX(1.2) scaleY(.85)}
  25%{transform:scaleX(.85) scaleY(1.15)}
  40%{transform:scaleX(1.1) scaleY(.92)}
  55%{transform:scaleX(.95) scaleY(1.05)}
  70%{transform:scaleX(1.03) scaleY(.98)}
  85%{transform:scaleX(.99) scaleY(1.01)}
  100%{transform:scale(1)}
}
@media(prefers-reduced-motion:reduce){
  .ab-09__btn:hover{animation:none;transform:scale(1.04)}
}

How this works

The jelly effect chains scaleX and scaleY transforms through a multi-step keyframe (ab-09-jelly): the button first squashes horizontally (scaleX(1.2) scaleY(.9)), then stretches vertically (scaleX(.85) scaleY(1.1)), and finally oscillates back through diminishing overshoot values before settling at scale(1). This mimics the physics of a jelly object being compressed and released. All transforms operate from the button's natural centre (transform-origin: center), so the effect stays spatially stable.

The animation is triggered by the :hover state, and because it ends at the identity transform, the button naturally returns to normal when the cursor leaves mid-animation. animation-fill-mode: both ensures the first frame is applied immediately on hover without a single frame at the resting state. Combining with a slight filter: brightness pulse makes the jelly feel more alive, as if it's reacting to light during deformation.

Customize

  • Intensify the jelly effect by increasing the extreme scale values (e.g. scaleX(1.35) for squash and scaleY(1.2) for stretch).
  • Add a colour flash during the peak squash by transitioning filter: hue-rotate(30deg) at the 20% keyframe step.
  • Create an idle bounce by adding a secondary animation: ab-09-idle 2s ease-in-out infinite with gentle scaleY(1.02) pulses between hover interactions.
  • Delay the jelly on staggered rows by giving each button an increasing animation-delay — e.g. 0s, .1s, .2s — for a wave effect across a button group.
  • Reduce the settle wobble for a tighter feel by cutting the oscillation keyframe count from 7 steps to 5, eliminating the final two minor overshoot steps.

Watch out for

  • The scaleX/scaleY combination can cause text to appear slightly blurry during the squash step on low-DPI screens — this is a sub-pixel rendering artefact and is usually imperceptible at normal viewing distances.
  • If the button is inside a card with overflow: hidden, the scale-up phase may be clipped — ensure the container has enough padding or use a wrapper with overflow: visible.
  • On Safari, combined scale transforms occasionally trigger a repaint of sibling elements — isolate the button in its own stacking context with isolation: isolate if you see neighbouring content flashing.

Browser support

ChromeSafariFirefoxEdge
36+ 9+ 16+ 36+

CSS transform animations are universally supported; the multi-step keyframe works in all modern engines.

Search CodeFronts

Loading…