20 CSS Ripple Effects

14 Pure CSS6 Light JSPublished 8 new designs · Updated on

A ripple has an origin and a lifecycle; a pulse has neither. These 20 hand-coded ripple animations cover the expanding ring as a primitive: origin from click coordinates, keeping the ring circular in a non-square box, overlapping rings without stacking, easing that decelerates like real displacement, and cleanup so long lists do not leak. Every production path animates transform and opacity only. Each is scoped under its own .rpl-NN class, guards motion behind prefers-reduced-motion, and is framework-agnostic copy-paste code.

Related36 CSS Button Hover Effects16 CSS Pulse Animations30 CSS Keyframe Animations

Course pickPartner: Zero to Mastery

Affiliate link

Want to build production-ready CSS layouts, animations and UI from scratch?

You just browsed 20 ripple effects. Learn the Flexbox, Grid and animation thinking behind them, so the next component starts in your head, not in a copy-paste.

10% off at checkout with code
Check ZTM Course

Every ZTM course in one membership: $25/month, paid yearly at $299 · 30‑day money-back guarantee

The CSS Bootcamp. We may earn a commission, at no extra cost to you.

01. Ripple Origin from Click Coordinates (opens in a new tab)

Published

Light JSNEW
A click carries two numbers and a ripple needs exactly those two. This build reads the pointer position against the container box, writes it into two custom properties, and scales a ring from zero to a radius computed to reach the furthest corner. The readout prints the coordinates and the radius as you click, including the case where a too-small radius leaves a corner untouched.

02. Keeping Ripples Circular in Any Box (opens in a new tab)

Published

Pure CSSNEW
A ring sized in percentages goes oval the instant its container stops being square, and almost no container is square. The failure sits beside three fixes: a square pseudo-element driven by aspect-ratio, an absolute size taken from the container diagonal, and the padding-top percentage trick for engines that predate aspect-ratio. All three are labelled.

03. Overlapping Ripples Without Stacking (opens in a new tab)

Published

Pure CSSNEW
Fire rings faster than they fade and their alphas add until the surface is a solid disc. The cure is compositing, not arithmetic: cap the concurrent count, front-load the opacity decay so each ring loses most of its weight early, and blend with screen so overlap reads brighter rather than denser. One, three and eight rings run side by side.

04. Ripple Easing That Feels Like Water (opens in a new tab)

Published

Pure CSSNEW
Real displacement decelerates hard: fast at impact, then trailing away. A linear ripple reads as a machine and ease-in-out reads as a slide transition. The same ring runs under three curves with each curve drawn beside it, plus the detail most builds miss — scale and opacity want different timing, so the ring is still growing after it has almost gone.

05. Compositor Only Ripples at Sixty FPS (opens in a new tab)

Published

Pure CSSNEW
Animating width, height or top puts layout on the critical path for every single frame; animating transform and opacity hands the work to the compositor. The two versions run side by side with the properties named and the pipeline stages each one triggers marked, plus an honest account of what will-change actually buys and what it costs.

06. Ripple Cleanup and Memory in Long Lists (opens in a new tab)

Published

Light JSNEW
Every click that appends a ring leaves a node behind unless something removes it. This build shows the animationend listener with once: true, the fallback timeout for when the animation never fires at all, and a live count of ripple nodes so the leak is visible. The rows share one delegated listener, because 500 rows means 500 listeners otherwise.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

07. Ripple on Touch Without the Tap Delay (opens in a new tab)

Published

Light JSNEW
Bind a ripple to click and on touch it can arrive hundreds of milliseconds after the finger, long after the user decided the tap did not register. The fix is to split feedback from action: pointerdown draws the ring, click still performs the work. The two traps come with it — pointerdown also fires when a scroll begins, and a ring that started must still finish.

08. Accessible Ripples and Reduced Motion (opens in a new tab)

Published

Pure CSSNEW
A ripple is decorative feedback, so under reduced motion the answer is not a slower ripple — it is an instant state change that says the same thing without movement. Both versions sit side by side. Alongside them: why the ring must be aria-hidden, why it can never be the only sign a control fired, and why it is not a focus indicator.

09. Water Surface Click Ripple (opens in a new tab)

PublishedUpdated

Light JS
Three concentric rings leave the same point a beat apart, each one wider, slower and fainter than the last. That stagger is what separates a water ripple from a single expanding circle: the surface is still responding after the first ring has gone. Coordinates come from the container box, easing comes from the tuned displacement curve.

10. Material Ink Button Ripple (opens in a new tab)

PublishedUpdated

Light JS
Ink spreads from the exact point of the press and is clipped to the button's own shape, which is where most implementations fall over. Four button types share one script: filled, outlined, text and icon. The clipping rules, the interaction between border-radius and the overflow clip, and the centred-origin exception for icon buttons are all shown.

11. Pond Background with Drifting Ripples (opens in a new tab)

PublishedUpdated

Pure CSS
Nine rings surface at scattered positions on a slow, uneven cycle, so the field never reads as a grid or a pulse. No interaction and no script: the origins are authored per ring as custom properties. It also covers what an always-on background animation actually costs, and why it has to stop under reduced motion.

12. Neon Glow Ripple Ring (opens in a new tab)

PublishedUpdated

Pure CSS
The glow is a second ring, blurred, sitting behind the sharp one — not a filter applied to the ring itself. Filtering the ring blurs the edge you were trying to keep crisp, which is the whole difference between neon and fog. Both versions run side by side so the failure is visible, on a near-black ground where a glow can actually be seen.

13. Ripple Loading Spinner (opens in a new tab)

PublishedUpdated

Pure CSS
Four rings leave the same centre on a fixed interval, producing a continuous outward flow with nothing rotating. The interesting part is the arithmetic: the delay per ring is the cycle divided by the ring count, so adding a fifth ring keeps the rhythm even instead of bunching it. Paired with a live region, because a spinner alone announces nothing.

14. Sonar Ping Status Ripple (opens in a new tab)

PublishedUpdated

Pure CSS
A ping leaves a status dot and travels outward, twice per cycle. Built as a monitoring panel where every row carries a text state as well as a colour and a motion, because a green dot next to a red dot is the textbook failure of SC 1.4.1 — colour and animation are decoration, the word is the information.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

15. Heartbeat Pulse Ripple (opens in a new tab)

PublishedUpdated

Pure CSS
A heartbeat is not an even throb, it is lub-dub: two beats close together, then a longer gap. That asymmetry lives entirely in the keyframe percentages. Rings leave the sensor point in the same two-beat envelope, laid over a clinical trace panel where the beat interval is stated in numbers as well as motion.

16. Ripple Card Hover Reveal (opens in a new tab)

PublishedUpdated

Pure CSS
A ripple opens from the card's corner and carries a state change with it — the detail row that was hidden. The gate matters more than the effect: without @media (hover: hover) a touch device fires the hover state on tap and leaves it stuck, so the card ends up in a state the user cannot exit. Focus-within gets the same reveal for keyboard users.

17. Sound Wave Ripple Visualizer (opens in a new tab)

PublishedUpdated

Pure CSS
Rings leave a centre point at different amplitudes, each band driven by its own custom property, so the field reads as radial displacement rather than a row of bars. It is decorative and says so: nothing here is connected to Web Audio, and a visualiser that is not synced to real audio should never be presented as if it were.

18. Liquid Drop Impact Ripple (opens in a new tab)

PublishedUpdated

Pure CSS
A drop falls, hits, throws rings outward, and a smaller rebound drop rises from the impact point and lands again. Three animations sequenced with nothing but delays computed from one cycle token, so the whole event stays in phase, cannot drift apart over successive loops, and can be retimed end to end by changing a single value.

19. Ripple Login Form Interaction (opens in a new tab)

PublishedUpdated

Light JS
Ripple feedback on real form controls: a labelled email field, a password field, a remember checkbox and a submit button. The ripple confirms that a control received the press and nothing more — validation is text, tied to the field with aria-describedby, because a ring that flashes and vanishes is not an error message.

20. Aurora Ripple Background (opens in a new tab)

PublishedUpdated

Pure CSS
Very slow colour rings drift across a dusk gradient, overlapping into an aurora. The real problem is not the effect, it is the text: body copy over shifting colour has a contrast ratio that changes frame by frame. Solved with a fixed panel and a scrim measured against the worst frame, not the best one.
FAQ

Frequently asked questions

What is the difference between a ripple and a pulse?
A ripple has an origin and a lifecycle: it is born at a point, expands outward, fades as it grows, and dies. A pulse has neither — it scales in place and loops. That distinction decides which one you want. Feedback for a discrete activation, like a tap or a press, wants a ripple, because the expansion visually connects the effect to the exact place the person touched. An ongoing state, like a live indicator or a recording light, wants a pulse, because there is no single moment to originate from. Using a looping pulse where the interface needed activation feedback is the most common mix-up, and it makes a control feel like it is idling rather than responding.
How do you get a ripple to start where the user clicked?
Read the pointer position relative to the element and write it into two custom properties the animation reads as its centre. The subtlety is which coordinates to use. The offsetX and offsetY on a click event are measured against the event target, so a click that lands on a child element gives you coordinates in that child's box rather than the container's, and the ripple appears in the wrong place. Measuring with getBoundingClientRect on the ripple container and subtracting from clientX and clientY avoids that entirely. The other half is the radius: the ring has to reach the furthest corner from the origin, not the nearest edge, or a click near one side leaves a visible gap in the opposite corner.
Why does my ripple look like an oval instead of a circle?
Because it is sized in percentages inside a container that is not square. A percentage width and height resolve against different axes, so the shape stretches with the box, and border-radius of 50 percent on a stretched box gives an ellipse rather than a circle. Three fixes work. Give the ripple element an aspect-ratio of 1 and size it on one axis only. Size it from the container's diagonal as an absolute length, which is what you want anyway if the ring has to cover the furthest corner. Or, for older engines, use the percentage padding-top trick that predates aspect-ratio. All three keep the ring circular regardless of how the container is shaped.
How do you keep ripples at sixty frames per second?
Animate only transform and opacity. Those two are handled on the compositor and never touch layout, so the browser can run them off the main thread. Animating width, height, top or left forces the browser to recalculate layout on every frame, which is what produces the stutter people usually blame on the animation being too complex. A related trap is will-change: it is a hint that costs real memory, not a fix, and putting it on every ripple in a long list is worse than leaving it off entirely. Apply it to the small number of elements that genuinely need promoting, and remove it when the animation finishes.
Do JavaScript ripples leak memory?
They do if nothing removes them. The usual pattern appends a new element for each click and relies on the animation ending to clean it up, so an animationend listener registered with once true is the minimum. That alone is not enough, because the animation may never fire — a backgrounded tab can suspend it, and a reduced-motion rule can cancel it before it starts — so a fallback timeout that removes the node regardless is what makes it safe. The second leak is subtler: binding a listener to every row of a long list means hundreds of listeners for one behaviour. Delegate from a single container instead and read the target from the event.
Are ripples accessible?
Only if they are decoration rather than information. A ripple should be marked aria-hidden and must never be the only sign a control was activated — a screen-reader user gets nothing from it, and neither does anyone who has motion reduced. Under prefers-reduced-motion the right response is to replace the ripple with an instant state change rather than a slower ripple, because a brief background tint communicates the same acknowledgement with no movement at all. A ripple is also not a focus indicator: a control still needs a visible focus ring that meets the three-to-one contrast requirement, and a target still needs to be at least forty-four pixels.
When should you not use a ripple?
Whenever the interaction is not a discrete activation. Ripples are feedback for a moment — a tap, a press, a send — and they work because that moment is worth marking. Attaching one to every hover, every card and every container spends the same attention-grabbing device on things that did not need it, and the interface starts to feel restless. They are also a poor fit for anything the person did not initiate: a ripple that fires on a state change they did not cause reads as the interface twitching. If you cannot name the exact action a given ripple is acknowledging, it probably should not be there.

Related collections

20 CSS Animated Buttons preview

20 CSS Animated Buttons

20 hand-coded CSS animated buttons — neon glow, ripple, 3D press, liquid fill, jelly bounce, shine sweep, animated border, moving gradient CTA, text flip, submit success state, add-to-cart progress, download icon, hamburger-to-close, toggle switch, loading spinner inside button, next/prev arrow nav, and ghost button background reveal. Half pure CSS, half lightweight JS for production interactions.

11 CSS animation-timeline Demos preview

11 CSS animation-timeline Demos

11 pure CSS animation-timeline demos built on the W3C scroll() and view() spec — reading progress bar, view-timeline fade & reveal, shrinking sticky header, stacking cards, horizontal scroll section, parallax hero, container shadow indicators, reverse-scroll columns, text scrim reveal, cover card to sticky header, and image zoom / clip-path wipe. Zero JS, off the main thread, Core Web Vitals safe. Copy-paste ready.

25 CSS Background Animations preview

25 CSS Background Animations

25 hand-coded CSS background animations for SaaS hero sections, developer tool documentation, agency portfolios, gaming and Web3 landing pages, seasonal e-commerce campaigns, and dark-mode dashboards. Covers full-screen gradient shifts, animated mesh gradients, aurora borealis glow, cursor spotlight follow, interactive water ripples, dot grid and diagonal stripe patterns, SVG grain and noise texture overlays, topographic contour lines, layered SVG waves, plasma and lava lamp fluids, bokeh light blur, particle constellation networks, matrix digital rain, synthwave 3D perspective grids, starfield warp speed, CRT scanline overlays, fog and mist drift, morphing organic blobs, floating glassmorphism orbs, halftone dot patterns, starry night skies, floating geometric shapes, rising bubbles, and falling snow. 20 are pure CSS with zero JavaScript; the 5 that need it use vanilla canvas or pointer tracking with no dependencies. Every background animates compositor-only properties so it never blocks the main thread, is scoped under a .bga-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

Search CodeFronts

Loading…