SVG filters cookbook — what CSS can't do.
CSS filter gives you eight things: blur, brightness, contrast, hue-rotate, drop-shadow, grayscale, invert, sepia. Useful, but tiny. SVG filters give you everything else — liquid distortion, gooey blob effects, paper grain, ink bleed, chromatic aberration. Same filter: url(...) syntax. Way more power.
Every modern browser ships with the same SVG filter primitives: feTurbulence (noise), feDisplacementMap (warp by another image), feGaussianBlur (blur), feColorMatrix (channel math), feConvolveMatrix (sharpen / emboss / edge detect), and a dozen more. You define a filter once in an SVG, give it an ID, and apply with filter: url(#myFilter) from CSS.
Below are 8 production-ready recipes. Each is a <filter> definition + a CSS class that applies it. The SVG block at the top of the page (invisible, 0×0) holds all the filter defs.
Liquid distortion
Warps text or shapes with smooth fractal noise. Used for organic, watery, "morphing" effects. The scale controls how much warp.
<!-- in your SVG defs -->
<filter id="liquid">
<feTurbulence type="fractalNoise"
baseFrequency="0.015"
numOctaves="2"/>
<feDisplacementMap in="SourceGraphic"
scale="14"/>
</filter>
/* apply in CSS */
.liquid { filter: url(#liquid); }
Gooey blob menu
The "metaball" effect — circular elements merge into single blobs when close. The classic floating-action-button radial menu. feGaussianBlur blurs, feColorMatrix sharpens the alpha threshold.
<filter id="gooey">
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 18 -7"/>
</filter>
.gooey-container {
filter: url(#gooey);
}
.gooey-container .blob {
width: 40px; height: 40px;
border-radius: 50%;
background: var(--brand);
}
18 increases alpha contrast (sharper edges) and -7 shifts the alpha threshold (controls where merge happens). Adjust both for tighter or looser blob fusion.Paper grain overlay
The slight noisy texture that makes a flat background feel like printed paper or matte cardstock. feTurbulence at high frequency = fine grain.
<filter id="paper">
<feTurbulence type="fractalNoise"
baseFrequency="0.9"
numOctaves="3"/>
<feColorMatrix values="
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0.6 0"/>
</filter>
.card::after {
content: '';
position: absolute;
inset: 0;
filter: url(#paper);
background: rgba(255,255,255,0.6);
mix-blend-mode: overlay;
}
Ink bleed
For typography that should feel hand-printed. Slight displacement + mild blur = letterforms with imperfect edges, like newspaper ink.
<filter id="ink">
<feTurbulence baseFrequency="0.04"
numOctaves="2"/>
<feDisplacementMap in="SourceGraphic"
scale="3"/>
<feGaussianBlur stdDeviation="0.4"/>
</filter>
h1 { filter: url(#ink); }
Squiggle line
Convert any straight line into a hand-drawn wavy one. Useful for sketchy underlines, dividers, mock wireframes.
<filter id="squiggle">
<feTurbulence baseFrequency="0.06"
numOctaves="3"/>
<feDisplacementMap in="SourceGraphic"
scale="6"/>
</filter>
hr { filter: url(#squiggle); }
Soft neon glow
Better than text-shadow for headlines and logos. Combines blur with the source image — gives that "lit from within" feel.
<filter id="glow">
<feGaussianBlur stdDeviation="3" result="b"/>
<feMerge>
<feMergeNode in="b"/>
<feMergeNode in="b"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
.neon { filter: url(#glow); }
Chromatic aberration
Splits the red and blue channels by 2px in opposite directions — the "lens distortion" look. Hover state on retro-styled buttons or hero headlines.
<filter id="chroma">
<feOffset dx="-2" result="r"/>
<feColorMatrix in="r" values="
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0" result="rO"/>
<feOffset dx="2" result="b"/>
<feColorMatrix in="b" values="
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 1 0" result="bO"/>
<feMerge>
<feMergeNode in="rO"/>
<feMergeNode in="bO"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
Embossed surface
The feConvolveMatrix kernel is a 3×3 grid that performs edge detection / sharpening / embossing depending on the values. This kernel creates a soft top-left light, bottom-right shadow.
<filter id="emboss">
<feConvolveMatrix order="3"
kernelMatrix="
-2 -1 0
-1 1 1
0 1 2"/>
</filter>
.card { filter: url(#emboss); }
Performance note: SVG filters are GPU-accelerated on modern browsers, but expensive on large surfaces. Apply them to small elements (icons, headings, buttons) — not full-page backgrounds. feTurbulence in particular is heavy; cache the result with filter-region if you reuse the same noise multiple times.
Browser support is universal. Every modern browser implements the SVG Filter spec. If a filter works on desktop Chrome, it works on mobile Safari, Firefox, Edge — no fallback engineering needed.