Mercury Metaball
Elemental & Nature · Animated · pure CSS
A gooey SVG filter rims the letters with a liquid meniscus and fuses them with drifting satellite droplets that get pinched into the letterforms and absorbed, all wrapped in a silvery chrome gradient swept by a moving specular highlight and a cool reflective glow. Liquid mercury in motion — reflective, metallic and hypnotic, and it stays legible on dark or light backgrounds.
How it works
Mercury Metaball is an animated elemental & nature text effect rendered entirely in CSS. It relies on an inline SVG <defs> block (filters, gradients or clip-paths), which the HTML export carries alongside the CSS.
Controls
Mercury Metaball exposes 3 dedicated controls — Droplets, Drift and Tint — on top of the shared type controls (font, weight, letter-spacing and case). Open it in the generator to tune every value live, then copy the updated CSS.
CSS
/* Mercury Metaball — made with TEXT-FX · https://text-fx.app
* HTML: requires the inline <svg> filter defs — see the HTML export.
* Font: 'Bricolage Grotesque', sans-serif (load from Google Fonts).
*/
.text-effect {
font-family: 'Bricolage Grotesque', sans-serif;
font-weight: 900;
letter-spacing: 0px;
text-transform: none;
}
.text-effect {
position: relative;
display: inline-block;
padding: 0.7em 1.5em;
background: linear-gradient(100deg, hsl(210 25% 92% / 0) 40%, hsl(210 18% 97% / 0.85) 47%, hsl(210 8% 100% / 0.95) 50%, hsl(210 18% 97% / 0.85) 53%, hsl(210 25% 92% / 0) 60%), linear-gradient(180deg, hsl(210 5% 96%) 0%, hsl(210 13% 82%) 26%, hsl(210 23% 40%) 50%, hsl(210 13% 76%) 63%, hsl(210 7% 94%) 80%, hsl(210 13% 56%) 100%);
background-size: 260% 100%, 100% 100%;
background-position: 200% 0, 0 0;
background-repeat: no-repeat;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
filter: url(#text-effect-goo) drop-shadow(0 1px 1px hsl(210 30% 4% / 0.5)) drop-shadow(0 0 12px hsl(210 33% 62% / 0.5));
animation: text-effect-sheen 3.6s linear infinite;
}
.text-effect .fx-drop {
position: absolute;
left: 50%;
top: 50%;
width: var(--s);
height: var(--s);
border-radius: 50%;
background: radial-gradient(circle at 34% 30%, hsl(210 5% 98%) 0%, hsl(210 13% 80%) 34%, hsl(210 13% 54%) 78%, hsl(210 21% 40%) 100%);
pointer-events: none;
transform: translate(-50%, -50%) translate(var(--fx), var(--fy)) scale(0.55);
animation: text-effect-drift 6.4s ease-in-out infinite;
animation-delay: var(--delay);
}
@keyframes text-effect-sheen {
from { background-position: 200% 0, 0 0; }
to { background-position: -120% 0, 0 0; }
}
@keyframes text-effect-drift {
0% { transform: translate(-50%,-50%) translate(var(--fx), var(--fy)) scale(0.55); opacity: 0; }
6% { opacity: 1; }
20% { transform: translate(-50%,-50%) translate(calc(var(--fx) * 0.5), calc(var(--fy) * 0.5)) scale(1); opacity: 1; }
40% { transform: translate(-50%,-50%) translate(calc(var(--fx) * 0.12), calc(var(--fy) * 0.12)) scale(0.82); opacity: 1; }
48% { transform: translate(-50%,-50%) translate(0, 0) scale(0.26); opacity: 0; }
50% { transform: translate(-50%,-50%) translate(var(--gx), var(--gy)) scale(0.55); opacity: 0; }
56% { opacity: 1; }
70% { transform: translate(-50%,-50%) translate(calc(var(--gx) * 0.5), calc(var(--gy) * 0.5)) scale(1); opacity: 1; }
90% { transform: translate(-50%,-50%) translate(calc(var(--gx) * 0.12), calc(var(--gy) * 0.12)) scale(0.82); opacity: 1; }
98% { transform: translate(-50%,-50%) translate(0, 0) scale(0.26); opacity: 0; }
100% { transform: translate(-50%,-50%) translate(var(--fx), var(--fy)) scale(0.55); opacity: 0; }
}
HTML
This effect needs the markup below (per-letter spans, SVG defs, or a data-text attribute).
<!-- Made with TEXT-FX · https://text-fx.app -->
<style>
.text-effect {
font-family: 'Bricolage Grotesque', sans-serif;
font-weight: 900;
letter-spacing: 0px;
text-transform: none;
}
.text-effect {
position: relative;
display: inline-block;
padding: 0.7em 1.5em;
background: linear-gradient(100deg, hsl(210 25% 92% / 0) 40%, hsl(210 18% 97% / 0.85) 47%, hsl(210 8% 100% / 0.95) 50%, hsl(210 18% 97% / 0.85) 53%, hsl(210 25% 92% / 0) 60%), linear-gradient(180deg, hsl(210 5% 96%) 0%, hsl(210 13% 82%) 26%, hsl(210 23% 40%) 50%, hsl(210 13% 76%) 63%, hsl(210 7% 94%) 80%, hsl(210 13% 56%) 100%);
background-size: 260% 100%, 100% 100%;
background-position: 200% 0, 0 0;
background-repeat: no-repeat;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
filter: url(#text-effect-goo) drop-shadow(0 1px 1px hsl(210 30% 4% / 0.5)) drop-shadow(0 0 12px hsl(210 33% 62% / 0.5));
animation: text-effect-sheen 3.6s linear infinite;
}
.text-effect .fx-drop {
position: absolute;
left: 50%;
top: 50%;
width: var(--s);
height: var(--s);
border-radius: 50%;
background: radial-gradient(circle at 34% 30%, hsl(210 5% 98%) 0%, hsl(210 13% 80%) 34%, hsl(210 13% 54%) 78%, hsl(210 21% 40%) 100%);
pointer-events: none;
transform: translate(-50%, -50%) translate(var(--fx), var(--fy)) scale(0.55);
animation: text-effect-drift 6.4s ease-in-out infinite;
animation-delay: var(--delay);
}
@keyframes text-effect-sheen {
from { background-position: 200% 0, 0 0; }
to { background-position: -120% 0, 0 0; }
}
@keyframes text-effect-drift {
0% { transform: translate(-50%,-50%) translate(var(--fx), var(--fy)) scale(0.55); opacity: 0; }
6% { opacity: 1; }
20% { transform: translate(-50%,-50%) translate(calc(var(--fx) * 0.5), calc(var(--fy) * 0.5)) scale(1); opacity: 1; }
40% { transform: translate(-50%,-50%) translate(calc(var(--fx) * 0.12), calc(var(--fy) * 0.12)) scale(0.82); opacity: 1; }
48% { transform: translate(-50%,-50%) translate(0, 0) scale(0.26); opacity: 0; }
50% { transform: translate(-50%,-50%) translate(var(--gx), var(--gy)) scale(0.55); opacity: 0; }
56% { opacity: 1; }
70% { transform: translate(-50%,-50%) translate(calc(var(--gx) * 0.5), calc(var(--gy) * 0.5)) scale(1); opacity: 1; }
90% { transform: translate(-50%,-50%) translate(calc(var(--gx) * 0.12), calc(var(--gy) * 0.12)) scale(0.82); opacity: 1; }
98% { transform: translate(-50%,-50%) translate(0, 0) scale(0.26); opacity: 0; }
100% { transform: translate(-50%,-50%) translate(var(--fx), var(--fy)) scale(0.55); opacity: 0; }
}
</style>
<svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs>
<filter id="text-effect-goo" x="-70%" y="-120%" width="240%" height="340%">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur"/>
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 22 -10" result="goo"/>
<feComposite in="SourceGraphic" in2="goo" operator="over"/>
</filter>
</defs></svg>
<div class="text-effect">Your text<i class="fx-drop" style="--fx:2.52em;--fy:0em;--gx:-3.06em;--gy:0em;--s:0.34em;--delay:0s"></i><i class="fx-drop" style="--fx:-2.33em;--fy:0.94em;--gx:3.39em;--gy:-0.41em;--s:0.4em;--delay:-2.13s"></i><i class="fx-drop" style="--fx:0.33em;--fy:-1.67em;--gx:-3.4em;--gy:0.9em;--s:0.46em;--delay:-4.27s"></i></div>
- Category
- Elemental & Nature
- Type
- Animated
- Browser support
- SVG goo filter (feGaussianBlur + feColorMatrix) + background-clip:text metal fill
- Capabilities
- svgDefs