Liquid✨ Premium

Liquid Morph

Three drops in violet, pink and cyan (80, 70 and 50 px) orbit the center of a 280 × 160 px stage, sticking together and pulling apart every 4 s: an SVG "goo" filter written in the HTML blurs the stage then sharpens the edges again, so two nearby drops weld through a bridge of matter before they touch — CSS, zero JavaScript, frozen mid-merge when the user reduces motion.

CSSSVG FilterOrganique

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Liquid has 31 effects, including 6 free. Explore the category →

3 usage examples

1 L liquid soap refill — product page of an artisan soap maker — Liquid Morph example 1

① 1 L liquid soap refill — product page of an artisan soap maker

WhenThe shopper looks at the one-liter refill: the jug on the left, on the right the range's three scents as three drops that stick together and pull apart, with the price and the add-to-cart button below.
WhyThree drops grouped at the center that merge and split read as a thick liquid at a small scale: "soap to blend" comes across without a photo. Metaballs fills the whole frame, too big and too busy for a product page.
SettingsRoot without background over the cream backdrop, 280 × 160 px stage kept; drops recolored lavender #9b7fd4, verbena #bfcf4a and mint #3fbf9b; filter copied with the id k408-goo-1; loop offset (animation-delay: -2.4s) so it opens on the split; scent legend under the stage.
Essential oil blend — page of an herbalist's shop — Liquid Morph example 2

② Essential oil blend — page of an herbalist's shop

WhenPage of the "Breathe" blend: eucalyptus, ravintsara and peppermint, with their proportions and origin on the left, the three drops coming together at the center on the right.
WhyOne color per oil, and the merge shows three oils becoming a single preparation: exactly what the page sells. The legend on the left carries the names, and the stage stays wordless, as the filter requires.
SettingsEucalyptus #3fb4c8, ravintsara #7cbf4a, peppermint #e3ec7a on a dark green background; filter copied with the id k408-goo-2; animation-delay: -3.2s; list of the three oils with dots in matching colors.
Juice made of three syrups — menu of a juice bar — Liquid Morph example 3

③ Juice made of three syrups — menu of a juice bar

WhenMenu card for the "Tropique" (mango, passion fruit, lime): three colored drops cluster inside the card, above the price and the glass size.
WhyThe effect fits in a small box next to the drink's name; the orbiting motion suggests mixing without filling the screen, and a 280 × 160 px stage stays cheap even on a phone.
Settings300 px wide white card over an orange gradient; drops mango #ffb21a, passion fruit #7b3fa0, lime #86cc32; filter copied with the id k408-goo-3; animation-delay: -3.2s.

How it works

The root .fx-0408-root (#0a0a0f background, at least 300 px tall) holds two things. First, a 0 × 0 px <svg class="fx-0408-defs">, taken out of the flow, whose only job is to carry the <filter id="fx-0408-goo">. Then the stage .liquid-morph-stage, 280 × 160 px with no background, which gets filter: url(#fx-0408-goo) and centers three round .liquid-drop elements: violet #a855f7 at 80 px, pink #ec4899 at 70 px, cyan #06b6d4 at 50 px. Each has its own 4 s loop (ease-in-out): the violet one travels from −60 px to +20 px horizontally, the pink one from +60 px to −20 px, the cyan one from 40 px below the center to 20 px above, with a slight swell between ×0.95 and ×1.1. At the start of the loop, 45 px separate violet from pink; around 400 ms they meet; from 1 to 3 s all three overlap at the center, then each goes back its own way.

The filter is three lines long. feGaussianBlur stdDeviation="10" blurs the whole stage: each drop's edge turns into an opacity gradient, and between two nearby drops the two halos add up. feColorMatrix keeps the colors and rewrites opacity (last row 0 0 0 20 -9: opacity × 20 − 9): anything under 45% becomes transparent, anything above 50% becomes solid. The edge turns sharp again, and the area between two close drops where the combined halos pass the threshold becomes a solid bridge. feComposite operator="atop" finally redraws the original drops on top of that silhouette: colors stay crisp, only the bridge takes the blended tint of the blur. Measured on the horizontal axis 400 ms into the loop: 12 to 13 px of empty space between violet and pink without the filter, 0 px with it, identical in Chromium 151, Firefox 153 and WebKit 26. color-interpolation-filters="sRGB" keeps the blur, otherwise computed in linear light, from darkening the bridges.

Three choices hold the effect together. The stage has no background: the threshold would apply to it and turn it into a solid rectangle, leaving the drops no edge to weld. The filter lives in the HTML, with a prefixed id: url(#…) only looks inside the document, and Firefox stops drawing the stage altogether when the id cannot be found or the <svg> is display: none (measured: empty stage), while Chrome and Safari ignore the filter and show three flat disks. Finally, the filter has a cost: measured in Chromium with software rendering (no graphics card, the slowest case), it takes 0.87 ms per frame at the sold size versus 0.10 ms without it; the same stage scaled up four times (1,120 × 640 px, blur of 40) climbs to 15.7 ms per frame and halves the frame rate. The filter is made for a small stage, not for a full-screen background.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, a block scoped to .fx-0408-root stops the three loops and places the drops at −38 px, +38 px and 34 px below the center: a still image where the three drops are welded together, so the merge reads without motion. Measured: 0% of pixels change over 500 ms in Chromium, Firefox and WebKit (3.6% without the preference).
  • Decorative content: the stage carries no text and no information. The filter's <svg> is marked aria-hidden="true" and focusable="false", and the drops are empty div elements that screen readers skip. If the colors mean something (three scents, three ingredients), write it next to the stage, like the legend in the scenes above: do not put text inside the stage, the blur and threshold would make it unreadable.
  • Contrast: on the #0a0a0f background, the violet drop measures 5.0:1, the pink one 5.6:1 and the cyan one 8.1:1, above the 3:1 threshold for graphics. On a light background, darken the drops: the filter does not change colors.
  • Pace: a 4 s loop, with no flashing and no sudden change in brightness; the motion stays inside a 280 × 160 px frame.

Browser compatibility

CSS (filter: url() on an HTML element, transform animations) + a three-primitive SVG filter written in the HTML, zero JavaScript, no dependencies. Measured in Chromium 151, Firefox 153 and WebKit 26: same merge (solid bridge 400 ms into the loop), same stop under reduced motion. Two copies of the effect on one page, sharing the id, work in all three (identical filters); change the id if you tune one copy differently. Cost measured in Chromium with software rendering: 0.87 ms per frame at 280 × 160 px, 15.7 ms scaled up ×4.

Chrome 53+✓ Full
Firefox 35+✓ Full (the filter's svg must stay displayed)
Safari 9.1+✓ Full
Edge 79+✓ Full
Mobile iOS✓ Full
Android Chrome✓ Full, keep it small on low-end phones

Without SVG filters on HTML (very old browsers), the stage shows three crisp disks crossing each other, with no bridge: the motion remains. If you move the <svg> block to another page or hide it with display: none, Firefox stops drawing the stage entirely: keep the 0 × 0 px svg in the same page as the stage.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0408-root">
  <svg class="fx-0408-defs" width="0" height="0" aria-hidden="true" focusable="false">
    <filter id="fx-0408-goo" color-interpolation-filters="sRGB">
      <feGaussianBlur … stdDeviation="10" />
      <feColorMatrix … values="… 0 0 0 20 -9" />
      <feComposite in="SourceGraphic" in2="goo" operator="atop" />
    </filter>
  </svg>
  <div class="liquid-morph-stage">
    <div class="liquid-drop liquid-drop-1"></div> … (3 drops)
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Merge strength (HTML — stdDeviation="10" on feGaussianBlur) 10 The wider the blur, the earlier the bridge forms. Measured 300 ms into the loop (26 px gap without the filter): 27 px of gap left at 6, 22 px at 10, 0 px at 16; but at 16 the drops round off into a soft mass and the small cyan one shrinks. Stay between 8 and 14 for drops this size.
Threshold (HTML — last row of feColorMatrix, 0 0 0 20 -9) 20 −9 (threshold around 45 to 50% opacity) 18 -7 lowers the threshold: fatter drops and bridges (+10% measured area), earlier merge. 30 -14 gives drier edges and thinner bridges. Keep the second number at about half the first.
Colors (CSS — background of .liquid-drop, -2, -3) #a855f7, #ec4899, #06b6d4 The filter keeps colors as they are; only the bridge takes the blended tint of the blur. Neighboring colors read as one substance, opposite colors show the mixing better.
Speed (CSS — 4s in the three animation declarations) 4 s Change all three durations together to keep the drops in phase. 6 s gives a thicker substance, 2.5 s a bubbling one. The same negative animation-delay on all three shifts where the loop starts.
Stage and drop size (CSS — .liquid-morph-stage, .liquid-drop-1/2/3, keyframes) 280 × 160 px; drops of 80, 70 and 50 px; paths of 60 and 40 px To scale up, multiply the stage, the drops, the keyframe distances and the stdDeviation together. The filter's cost follows the area: at ×4 in width and height, the frame rate halves with software rendering.
Background (CSS — .fx-0408-root) #0a0a0f Change the root's background or remove it to set the drops on your page. Never give .liquid-morph-stage a background: the threshold would turn it into a solid rectangle.

FAQ

filter: url(#fx-0408-goo) points to an element of the document itself: the filter must sit in the page that holds the stage. Keep the <svg class="fx-0408-defs"> block as is, at 0 × 0 px. Measured: if the id cannot be found or the svg is set to display: none, Firefox stops drawing the stage entirely, while Chrome and Safari show three flat disks with no bridge. Two copies of the effect on the same page can share the id (identical filters); if you tune one differently, give it its own id and its own filter: url().
Metaballs computes the substance pixel by pixel on a canvas: six balls bounce across the whole frame, and the bridges come from a real distance field. Liquid Morph does the opposite: three drops in HTML and CSS, grouped at the center of a 280 × 160 px stage, welded by an SVG blur-and-threshold filter, with no JavaScript at all. Pick Liquid Morph for a small box next to a text or a price; Metaballs for an animated background that fills the whole frame.
That is not what it is for. The blur is recomputed every frame over the whole stage: measured in Chromium with software rendering, 0.87 ms per frame at the sold size, 15.7 ms for a stage four times wider and taller, and the frame rate drops by half. A graphics card lowers the cost, but it still follows the area. For a large background, prefer a canvas animation such as Metaballs; for Liquid Morph, keep the stage to a few hundred pixels.