20 CSS Animated Buttons09 / 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.
Published
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><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);
}
}.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);
}
}Here's a working CSS Animated Button from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Jelly Bounce Button Animation
Source: https://codefronts.com/motion/css-animated-buttons/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.
## HTML
```html
<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>
```
## CSS
```css
.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);
}
}
```Here's a working CSS Animated Button from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Jelly Bounce Button Animation
Source: https://codefronts.com/motion/css-animated-buttons/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.
## HTML
```html
<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>
```
## CSS
```css
.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.
Make it yours
- Intensify the jelly effect by increasing the extreme scale values (e.g.
scaleX(1.35)for squash andscaleY(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 infinitewith gentlescaleY(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.
Gotchas — read before shipping
- The
scaleX/scaleYcombination 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 withoverflow: visible. - On Safari, combined scale transforms occasionally trigger a repaint of sibling elements — isolate the button in its own stacking context with
isolation: isolateif you see neighbouring content flashing.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 36+ | 9+ | 16+ | 36+ |
CSS transform animations are universally supported; the multi-step keyframe works in all modern engines.