Liquid Simulation
The mouse repels fifteen DOM drops: the pool opens around the cursor and slowly reassembles at the centre when the cursor leaves (weak centering pull). An SVG goo filter (Gaussian blur + alpha threshold) merges overlapping drops into a homogeneous surface. Not to be confused with the Liquid category (fx-0391–0420) which uses canvas or WebGL.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →
3 usage examples



How it works
The "goo" technique relies on two SVG primitives applied to a container: feGaussianBlur (8 px blur) followed by feColorMatrix with a strong alpha contrast (0 0 0 18 −7). This CSS filter is applied to .ls385-sim via filter: url(#uid). The filter's id is unique per instance (randomly generated) to avoid conflicts when two copies coexist in the same page: uid = 'ls385-goo-' + Math.random().toString(36).slice(2,7).
The 15 drops (div.ls385-drop) are created at load time with a random size (30–70 px) and random initial positions inside the container. On every frame, each drop experiences: repulsion from the cursor (vx −= dx/dist × fo, fo = (110−dist)/110 × 0.45) when the cursor is within 110 px; a weak centering pull (vx += (cx−x) × 0.0006 × f) always active; a random jitter (vx += (rand−0.5) × 0.12); and damping (vx *= 0.96^f). When the cursor leaves, only the centering pull remains: drops slowly gather into a mass at the centre. The step is normalised to 60 fps: f = dt / 16.67. An IntersectionObserver pauses the loop off screen.
Accessibility
- Touch:
touchmoverepels drops around the finger, exactly like the cursor.touchendtriggers the gradual return to the centre. - Keyboard: the effect is purely decorative and does not respond to the keyboard.
- Reduced motion: under
prefers-reduced-motion: reduce, the loop does not start and drops remain in a fixed ring around the centre, visible through the goo filter that blends them slightly. - Difference from the Liquid category: Liquid effects (fx-0391 to fx-0420) use canvas or WebGL for surface effects, metaballs or refraction. This effect uses only DOM
divelements and an SVG filter, with no pixels drawn — it is a visual CSS/DOM simulation, not a graphic render.
Browser compatibility
DOM, CSS and SVG filter, no dependency. feGaussianBlur and feColorMatrix available in all modern browsers since Chrome 8, Firefox 3, Safari 6. filter: url(#id) on an HTML element requires Chrome 18+, Firefox 35+, Safari 9.1+. IntersectionObserver since Chrome 51, Firefox 55, Safari 12.1. Not verified on real Safari; expected full.
Without JavaScript, drops appear in a fixed ring with the goo filter active, blending them slightly. Without IntersectionObserver, the loop also runs off screen.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0385-root">
<div class="ls385-wrap">
<div class="ls385-sim"></div>
<svg class="ls385-svg" width="0" height="0" aria-hidden="true" focusable="false">
<filter>
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur"></feGaussianBlur>
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="goo"></feColorMatrix>
<feComposite in="SourceGraphic" in2="goo" operator="atop"></feComposite>
</filter>
</svg>
<span class="ls385-label" aria-hidden="true">Hover to merge the drops</span>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Drop count (JS — loop for(var i=0;i<15;i++)) |
15 | 8 gives a compact, less defined blob; 25 a smoother, richer surface. Beyond 30, the goo filter becomes slow on mobile. |
Cursor influence radius (JS — dist < 110) |
110 px | 150 px enlarges the repulsion zone for a wider opening; 70 px only reacts to the cursor very close up. |
Repulsion force (JS — factor 0.45) |
0.45 | 0.7 gives a very snappy flight with drops shooting outward; 0.2 a slow, gradual opening. |
Centering pull (JS — (cx−x) × 0.0006) |
0.0006 | 0.002 brings drops back quickly when the cursor leaves; 0.0001 lets them drift for a long time before regrouping. |
SVG blur (HTML — stdDeviation="8") |
8 | 12 gives softer merging and blurrier edges; 4 sharp outlines but merging visible only on contact. |
FAQ
div elements and an SVG filter: no pixels are drawn, everything is CSS and DOM. It is lighter but less realistic, and its rendering changes if filter: url() on HTML is not supported (Safari < 9.1).id on their SVG filters, which is invalid HTML (IDs must be unique). The browser no longer knows which one to use and may apply the first copy's filter to both, or to neither. A random ID resolves this conflict without numbering instances.background of each div.ls385-drop is an animatable CSS property. Use a @keyframes on each drop with staggered delays (animation-delay) for a rotating rainbow; or change the colour from JS on each frame to follow the displacement.