Published: April 8, 2025
The clip-path
property lets you change the shape of an element by clipping to
a circle, polygon, or even an SVG path. However, before Chrome 135 and Safari 18.4,
you had to choose between responsive
polygons, and more complex shapes that are not responsive using SVG paths.
With the new shape()
function, a clip-path
can clip the element to a
non-polygon shape which is also responsive.
Create a flag shape
As an example, compare creating a flag shape with clip-path: path()
and
clip-path: shape()
.
A flag shape is not exactly a polygon, as its top and bottom borders are cubic Bézier curves rather than straight lines or rounded corners.
Create the flag with clip-path: path()
A shape like this flag can be represented using an SVG path:
.flag {
clip-path: path(
"M 0 20 \
C 25 0 75 40 100 20 \
V 80 \
C 75 100 25 60 0 80 \
z");
}
To break this down, an SVG path is a series of path commands:
- Move to 0, 20.
- Curve to 100, 20, using control points (25,0 and 75, 40).
- Vertical line to 80.
- Curve to 0, 80, using control points (75,100 and 25,50).
- Close the path (line to 0,20).
This draws a flag shape, but all the units are in pixels. SVG can scale those pixels to a view-box, but in a way that would always look like a geometric scale of the whole shape.
For example, if you wanted the whole rectangle to scale, but maintain the height and width of the curves 20px, SVG wouldn't be up to the task.
Create the flag with shape()
Compare the same result using shape()
. The shape function accepts a series of
commands, similar to the SVG path commands. However, these commands accept CSS
lengths and percentages, in any CSS unit.
The following CSS converts the flag a shape()
with percentage units:
.flag {
clip-path: shape(from 0% 20%,
curve to 100% 20% with 25% 0% / 75% 40%,
vline to 80%,
curve to 0% 80% with 75% 100% / 25% 60%,
close
);
}
Make it responsive
With the full range of CSS lengths available, you can pick which ones to use for each coordinate.
For example, to make the entire size of the flag scale by the element's size, but keep the height of the curve constant, you can do the following:
.flag {
clip-path: shape(from 0% 20px,
curve to 100% 20px with 25% 0% / 75% 40px,
vline to calc(100% - 20px),
curve to 0% calc(100% - 20px)
with 75% 100% / 25% calc(100% - 40px),
close
);
}
Add custom properties and animations
With the shape now defined in CSS, you can also use custom properties, to make it easy to manipulate the height:
.flag {
--wave-height: 40px;
clip-path: shape(
from 0px var(--wave-height),
curve to 100% var(--wave-height)
with 25% 0px / 75% calc(var(--wave-height) * 2),
vline to calc(100% - var(--wave-height)),
curve to 0 calc(100% - var(--wave-height))
with 75% 100% / 25% calc(100% - var(--wave-height) * 2),
close
)
}
You can even animate the CSS property using the @property
descriptor, and clamp it so that it doesn't overreach:
@property --animated-wave-height {
syntax: "<length>";
inherits: false;
initial-value: 40px;
}
@keyframes curve {
from { --animated-wave-height: 0px; }
to { --animated-wave-height: 180px; }
}
.flag {
width: 600px;
height: 400px;
background: green;
animation: curve 1s infinite alternate;
--wave-height: calc(min(var(--animated-wave-height, 40px), 40%));
clip-path: shape(
from 0px var(--wave-height),
curve to 100% var(--wave-height)
with 25% 0px / 75% calc(var(--wave-height) * 2),
vline to calc(100% - var(--wave-height)),
curve to 0 calc(100% - var(--wave-height))
with 75% 100% / 25% calc(100% - var(--wave-height) * 2),
close
)
}
Try the demo
In Chrome 135 or Safari 18.4, you can see the animating flag shape created using
clip-path: shape()
in
this CodePen demo.
Summary
clip-path: shape()
lets you clip your element using arbitrary and
responsive shapes, previously only possible using techniques like conic
gradients or JavaScript-constructed SVG.
Check the specification for the full syntax.
At the moment, it only works for clip-path
. In the future, we envision using
this kind of shape for
setting the shape of the element's border,
which would unlock even more non-rectangular ways of expression.