AI CSS Animations

Bubble Button

Soda bubbles fizz up through the button while you hover, each on its own size, path and beat, and pop as they reach the top edge. Eight spans on one keyframe, clipped by the button.

Also known as: bubbles hover effect, fizzy button css, rising bubbles animation.

HTML

<button class="btn-bubbles">
  <span class="btn-bubbles-fizz" aria-hidden="true"><i style="--i:0"></i><i style="--i:1"></i><i style="--i:2"></i><i style="--i:3"></i><i style="--i:4"></i><i style="--i:5"></i><i style="--i:6"></i><i style="--i:7"></i></span>
  <span class="btn-bubbles-label">Say cheers</span>
</button>

CSS

.btn-bubbles {
  --c: var(--btn-color, #3b82f6);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  font: 600 var(--btn-size, 18px)/1.2 system-ui, sans-serif;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  padding: 0.85em 2em;
  border: 0;
  border-radius: 0.8em;
  background: linear-gradient(to top, color-mix(in srgb, var(--c) 80%, #000), var(--c));
  color: #fff;
  transition: box-shadow 0.3s ease;}
.btn-bubbles-label { position: relative; }
.btn-bubbles-fizz i {
  position: absolute;
  bottom: -0.9em;
  left: calc(5% + var(--i) * 12%);
  width: 0.65em;
  height: 0.65em;
  border: 1px solid rgba(255, 255, 255, 0.85);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.9) 0 18%, rgba(255, 255, 255, 0.18) 28%);
  opacity: 0;
}
.btn-bubbles-fizz i:nth-child(odd) { width: 0.45em; height: 0.45em; }
.btn-bubbles-fizz i:nth-child(3n) { width: 0.85em; height: 0.85em; }
.btn-bubbles:is(:hover, :focus-visible) { box-shadow: 0 0.4em 1em color-mix(in srgb, var(--c) 35%, transparent); }
.btn-bubbles:is(:hover, :focus-visible) .btn-bubbles-fizz i {
  animation: btn-bubbles-rise 1.5s cubic-bezier(0.4, 0, 0.8, 0.6) calc(var(--i) * 0.13s) infinite;
}
.btn-bubbles:is(:hover, :focus-visible) .btn-bubbles-fizz i:nth-child(even) { animation-duration: 1.8s; }
@keyframes btn-bubbles-rise {
  0%   { opacity: 0; transform: translate(0, 0) scale(0.6); }
  15%  { opacity: 1; }
  45%  { transform: translate(0.3em, -1.5em) scale(0.85); }
  80%  { opacity: 1; }
  100% { opacity: 0; transform: translate(-0.15em, -3.8em) scale(1.15); }
}

@media (prefers-reduced-motion: reduce) {
  .btn-bubbles, .btn-bubbles *, .btn-bubbles::before, .btn-bubbles::after, .btn-bubbles *::before, .btn-bubbles *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --btn-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --btn-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 18px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar buttons