Making Blobby Shapes with Frontend Tooling
Blob shapes are those smooth, irregular, jelly-like figures popular as background flourishes and decorative elements on modern sites. While any illustration app can produce them, building them in code means they stay crisp, scalable, and easy to tweak. CSS and SVG both offer viable routes, each with its own trade-offs.
The SVG Circle Route
The simplest SVG shape is the <circle> element, which needs just a few attributes:
<circle cx="100" cy="100" r="40" fill="red" />
Those attributes map to geometry basics:
cxandcyset the x- and y-coordinates of the circle's center, relative to the top-left corner of the container.rdefines the radius.fillassigns the color.
That snippet yields a circle with a 40px radius centered at (100, 100). Multiple overlapping circles can build an interesting composite shape, as long as they stay within the bounds of the enclosing <svg> element, whose width and height define the artboard. Anything drawn beyond those bounds gets clipped.
<svg height="300" width="300">
<circle cx="80" cy="80" r="40" fill="red" />
<circle cx="120" cy="80" r="40" fill="red" />
<circle cx="150" cy="80" r="40" fill="red" />
<circle cx="150" cy="120" r="40" fill="red" />
<circle cx="100" cy="100" r="40" fill="red" />
</svg>
For less uniform, more organic shapes, swap <circle> for <ellipse>:
<ellipse cx="200" cy="80" rx="100" ry="50" fill="red" />
The ellipse element accepts separate rx and ry values for horizontal and vertical radii. It's effectively a superset of the circle — set both radii equal and you have a perfect circle.
If all you need is a plain circle, you don't even need SVG. Any HTML element can become elliptical with CSS border-radius:
.circle {
border-radius: 50%;
height: 50px;
width: 50px;
}
Freeform Shapes with SVG Paths
For truly irregular blobs, the SVG <path> element is the tool of choice. The path data, held in the d attribute, reads like a series of drawing commands:
M— Move to a starting pointL— Draw a straight lineC— Draw a cubic curveQ— Draw a quadratic Bézier curveZ— Close the path back to its start
Curves are where blob shapes happen. The C command takes a starting coordinate, then two control points that act as virtual "handles" pulling the curve toward them, then an endpoint. This structure makes drawing organic curves with multiple inflection points entirely feasible.

<path> element.Path coordinates read like map reference numbers at first glance:
<svg xmlns="http://www.w3.org/2000/svg">
<path
fill="#24A148"
d=""
/>
</svg>
<path d="M 10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>
That path starts at (10, 10) via M, then draws a cubic Bézier curve with control points (20, 20) and (40, 20) ending at the final coordinate. Reshaping any portion of the blob means adjusting a handful of coordinate pairs — no visual editor required.

A Handy Shortcut for Blob Paths
Hand-rolling dozens of curve coordinates is tedious, even if you understand each one. Blob-shaped profiles are complex enough that generated SVGs from a tool like blobmaker.app are a reasonable alternative that still leaves the result fully editable in code.
Putting Goo on Elements with SVG Filters
You can get blobby results from plain HTML elements too. Start with a couple of intersecting rectangles in the same color and apply SVG blur filters. The overlapping zone softens into something that looks like a real blob rather than geometry.

SVG filters live inside a <filter> wrapper and use a set of specialized filter primitives:
<feGaussianBlur><feImage><feMerge><feColorMatrix>
The two in play here are <feGaussianBlur> and <feColorMatrix>. Their key arguments are in, which accepts SourceGraphic to blur the shape itself or SourceAlpha to blur just the alpha channel, and stdDeviation, measured in standard deviations for the blur distribution.
circle {
filter: url("#id_of_filter");
}
This blur step defines the gooey look:
<feGaussianBlur in="SourceGraphic" stdDeviation="30" />
The filter is declared in markup but only applies when referenced as a CSS filter value on the blob's parent element, using its id.
<!-- The SVG filter -->
<svg style="position: absolute; width: 0; height: 0;">
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="30" />
</filter>
</svg>
<!-- The blob -->
<div class="hooks-main">
<div></div>
<div></div>
</div>
/* Blob parent element */
.hooks-main {
position: absolute;
width: 100%;
height: 100%;
filter: url("#goo&");
overflow: hidden;
}
Blur alone leaves edges scattered and color washy. The fix sits in <feColorMatrix>, which takes a matrix in its values attribute and re-maps every pixel's color and alpha values by multiplication. The matrix has five columns — RGBA channels plus a constant — and four rows:
[F-red1 F-green1 F-blue1 F-alpha1 F-constant1
F-red2 F-green2 F-blue2 F-alpha2 F-constant2
F-red3 F-green3 F-blue3 F-alpha3 F-constant3
F-red4 F-green4 F-blue4 F-alpha4 F-constant4]
Multiplying a pixel's RGBA values by the identity matrix leaves them unchanged; shifting matrix coefficients changes the color and/or alpha output.
new pixel color value = ( values matrix ) × ( current pixel color value )
A blob-friendly matrix looks like this:
| Values Matrix | Color Pixel (RGBA) | New Color (RGBA) | ||
|---|---|---|---|---|
[1 0 0 0 0 | × | [214 | = [ 214x1 + 232x0 + 250x0 + 1x0 + 1x1 | = [214 |
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="30" />
<feColorMatrix
in="blur"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 30 -7"
/>
</filter>
Those filter settings work on other shapes, making transformation a matter of copying the values rather than redrawing geometry.
Organic Corners with border-radius
Pure CSS also handles blob aesthetics, thanks to how border-radius splits each corner into two radii — one per adjoining edge. The shorthand sets all corners uniformly:
.rounded {
border-radius: 25%;
}
Blobs require asymmetry, which calls for the longhand corner properties instead:

Each property takes two values, one per edge of that corner:
.element {
border-top-left-radius: 70% 60%;
border-top-right-radius: 30% 40%;
border-bottom-right-radius: 30% 60%;
border-bottom-left-radius: 70% 40%;
}
Using different values on each corner yields varying levels of roundness across an element. You can tune the four corner configurations individually until the silhouette reads as a blob rather than a rounded square. The resulting shape can then accept a background, a gradient fill, or box-shadow effects.



