The CSS shape()
function recently gained support in both Chromium and WebKit browsers. It’s a way of drawing complex shapes when clipping elements with the clip-path
property. We’ve had the ability to draw basic shapes for years — think circle
, ellipse()
, and polygon()
— but no “easy” way to draw more complex shapes.
Well, that’s not entirely true. It’s true there was no “easy” way to draw shapes, but we’ve had the path()
function for some time, which we can use to draw shapes using SVG commands directly in the function’s arguments. This is an example of an SVG path pulled straight from WebKit’s blog post linked above:
<svg viewBox="0 0 150 100" xmlns="http://www.w3.org/2000/svg">
<path fill="black" d="M0 0 L 100 0 L 150 50 L 100 100 L 0 100 Q 50 50 0 0 z " />
</svg>
Which means we can yank those <path>
coordinates and drop them into the path()
function in CSS when clipping a shape out of an element:
.clipped {
clip-path: path("M0 0 L 100 0 L 150 50 L 100 100 L 0 100 Q 50 50 0 0 z");
}
I totally understand what all of those letters and numbers are doing. Just kidding, I’d have to read up on that somewhere, like Myriam Frisano’s more recent “Useful Recipes For Writing Vectors By Hand” article. There’s a steep learning curve to all that, and not everyone — including me — is going down that nerdy, albeit interesting, road. Writing SVG by hand is a niche specialty, not something you’d expect the average front-ender to know. I doubt I’m alone in saying I’d rather draw those vectors in something like Figma first, export the SVG code, and copy-paste the resulting paths where I need them.
The shape()
function is designed to be more, let’s say, CSS-y. We get new commands that tell the browser where to draw lines, arcs, and curves, just like path()
, but we get to use plain English and native CSS units rather than unreadable letters and coordinates. That opens us up to even using CSS calc()
-ulations in our drawings!
Here’s a fairly simple drawing I made from a couple of elements. You’ll want to view the demo in either Chrome 135+ or Safari 18.4+ to see what’s up.
So, instead of all those wonky coordinates we saw in path()
, we get new terminology. This post is really me trying to wrap my head around what those new terms are and how they’re used.
In short, you start by telling shape()
where the starting point should be when drawing. For example, we can say “from top left
” using directional keywords to set the origin at the top-left corner of the element. We can also use CSS units to set that position, so “from 0 0
” works as well. Once we establish that starting point, we get a set of commands we can use for drawing lines, arcs, and curves.
I figured a table would help.
Command | What it means | Usage | Examples |
---|---|---|---|
line | A line that is drawn using a coordinate pair | The by keyword sets a coordinate pair used to determine the length of the line. | line by -2px 3px |
vline | Vertical line | The to keyword indicates where the line should end, based on the current starting point.The | vline to 50px |
hline | Horizontal line | The to keyword indicates where the line should end, based on the current starting point.The | hline to 95% |
arc | An arc (oh, really?!). An elliptical one, that is, sort of like the rounded edges of a heart shape. | The to keyword indicates where the arc should end.The The | arc to 10% 50% of 1% |
curve | A curved line | The to keyword indicates where the curved line should end.The | curve to 0% 100% with 50% 0% |
smooth | Adds a smooth Bézier curve command to the list of path data commands | The to keyword indicates where the curve should end.The The | I have yet to see any examples of this in the wild, but let me know if you do, and I can add it here. |
The spec is dense, as you might expect with a lot of moving pieces like this. Again, these are just my notes, but let me know if there’s additional nuance you think would be handy to include in the table.
Oh, another fun thing: you can adjust the shape()
on hover/focus. The only thing is that I was unable to transition
or animate it, at least in the current implementation.
CSS shape() Commands originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.