I have spent too many hours wrestling with SVG viewBoxes just to get a wavy divider onto a client’s site. For years the choice was clip-path: polygon() or an external image, and both were compromises. The CSS shape function finally moves us off those hacks.
The old path() string was a black box of SVG data. The shape() function uses a syntax a developer can read: you set a starting point, then issue commands like move to, line to and curve to. It is precise, and it took long enough to land in browsers.
Why the CSS shape function matters
Circles and rounded rectangles are CSS 101. Hand a developer a blob or a torn paper edge, though, and the usual answer has been an <svg> element. SVGs do not scale gracefully with their containers on their own, so you end up doing extra math to make them behave.
The CSS shape function lets us define those paths in the stylesheet instead. The command that does the interesting work is curve to. Move its control points around and you get the irregular, hand-drawn looking shapes designers keep asking for.
The logic behind the curve
The hard part of the CSS shape function is the math behind smoothness. Two adjacent curves only look continuous when the end point of the first sits on the segment formed by the control points of both. Miss that and you get a visible kink at the join, which is exactly the sort of thing QA files tickets about.
To keep it manageable, I define my points as midpoints between control points. That cuts the randomness and keeps the curvature fluid. There is more on UI corners in my guide to CSS corner-shape properties.
From static shapes to animation
The gotcha shows up when you try to animate. I once tried to animate a clip-path polygon with 10 points into one with 12, and the browser gave up and snapped straight to the end state with no transition at all.
With shape(), the browser can interpolate the positions as long as your granularity (the number of curve commands) is identical between the two states. That is how the liquid, squishy button effects are built.
/* The Naive Approach: This won't animate smoothly if P points vary */
.element {
clip-path: shape(from 0% 0%, curve to 100% 0% with 50% 10%);
}
/* The Senior Approach: Keep granularity fixed */
@keyframes bbioon_wiggle {
0% {
clip-path: shape(from 0% 0%, curve to 100% 0% with 50% 10%);
}
100% {
clip-path: shape(from 0% 0%, curve to 100% 0% with 50% -10%);
}
}
A consistent command count also means you can drive the shape from scroll-driven animations and have a wavy divider react as the reader moves down the page. A static SVG cannot do that.
Refactoring your workflow
I am a pragmatist. I built several CSS generators because working out a 20-point blob by hand is a waste of billable hours. Take the code, but know what it is doing: plotting midpoints and offsets in a relative coordinate system.
If the CSS shape function work is eating your dev hours, I can take it over. I have been wrestling with WordPress and front-end performance since the 4.x days.
Dropping the SVG hacks
Rectangular thinking is no longer the only option in CSS. Squishy buttons, organic frames, wavy section edges: the CSS shape function handles all of it without an extra asset. For the full spec, go to the MDN basic-shape documentation, then go back and clear out the legacy SVG hacks.