← Back to gallery
CSS

Button Ripple Radial Gradient Fill

A press-feedback ripple driven by an animated radial-gradient layer inside an overflow-hidden button, with pointer-tracked origin and a pure CSS centered fallback.

Duration
1s
Resolution
1440×900
Format
CSS
ripplebutton-clickradial-gradientpointer-origincss-only

Interaction / radial-gradient / button press

Button ripple radial-gradient fill

Reimplements press-feedback ripples using an animated radial-gradient layer clipped to the button bounds, with pointer-tracked origin and a centered CSS-only fallback.

pointer-tracked0.65s bloom

Bloom from click origin

Pointer-Tracked

JS reads pointerdown coordinates and drives two CSS custom properties so the gradient center blooms from exactly where the user pressed.

  • pointer coords
  • custom properties
  • wide button

Pure CSS pressed state

Centered Pulse

A smaller action button fills from its geometric center on :active, avoiding any JS and keeping the effect deterministic across devices.

  • :active
  • centered
  • no JS

Emphasis button hover bloom

Ambient Burst

On hover the background auto-rotates a broader radial burst to call attention to a primary call-to-action while click keeps the tighter press ripple.

  • hover
  • CTA
  • wide stops

Ripple inspector

Pointer-Tracked

Press the button to replay the ripple.

Origin
pointer coords
Bloom
160px spread · 0.65s

Works well when buttons are wide enough for users to notice the origin — the ripple feels directly caused by the press rather than generic feedback.

css
.ripple-button {
  position: relative;
  overflow: hidden;
  background: #1e3a5f;
  color: white;
  border: 0;
  border-radius: 999px;
  padding: 12px 22px;
  isolation: isolate;
}

.ripple-button::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(circle 160px at var(--ripple-x, 50%) var(--ripple-y, 50%), rgba(125, 211, 252, 0.55) 0%, transparent 70%);
  opacity: 0;
  transform: scale(0.2);
  transition: opacity 0.65s ease-out,
              transform 0.65s ease-out;
  pointer-events: none;
  z-index: -1;
}

.ripple-button.is-rippling::after {
  opacity: 1;
  transform: scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .ripple-button::after { transition-duration: 0s; }
}