Creating CSS Shapes is a basic and certainly one of my favourite train. Certainly, I’ve one of many largest collections of CSS Shapes from the place you’ll be able to simply copy the code of any form. I additionally wrote an intensive information on how you can create them: The Trendy Information For Making CSS Shapes.
Even when I’ve detailed many of the trendy methods and methods, CSS retains evolving, and new stuff at all times emerges to simplify our developer life. Not too long ago, clip-path
was upgraded to have a brand new form()
worth. An actual recreation changer!
Earlier than we soar in, it’s price calling out that the form()
operate is presently solely supported in Chrome 137+ and Safari 18.4+ as I’m scripting this in Could 2025.
form()
?
What’s Let me quote the outline from the official specification:
Whereas the
path()
operate permits reuse of the SVG path syntax to outline extra arbitrary shapes than allowed by extra specialised form features, it requires writing a path as a single string (which isn’t appropriate with, for instance, constructing a path piecemeal with var()), and inherits plenty of limitations from SVG, akin to implicitly solely permitting the px unit.The
form()
operate makes use of a set of instructions roughly equal to those utilized bypath()
, however does so with extra customary CSS syntax, and permits the total vary of CSS performance, akin to extra items and math features.
In different phrases, we’ve the SVG options within the CSS aspect that we are able to mix with present options akin to var()
, calc()
, completely different items, and so on. SVG is already good at drawing advanced shapes, so think about what is feasible with one thing extra highly effective.
In the event you maintain studying the spec, you will discover:
In that sense,
form()
is a superset ofpath()
. Apath()
might be simply transformed to aform()
, however to transform aform()
again to apath()
or to SVG requires details about the CSS surroundings.
And guess what? I already created a web-based converter from SVG to CSS. Save this instrument as a result of it will likely be very useful. In case you are already good at creating SVG shapes or you’ve got present codes, no must reinvent the wheel. You paste your code within the generator, and also you get the CSS code that you may simply tweak later.
Let’s strive with the CSS-Tips brand. Right here is the SVG I picked from the web site:
<svg width="35px" top="35px" viewBox="0 0 362.62 388.52" >
<path d="M156.58,239l-88.3,64.75c-10.59,7.06-18.84,11.77-29.43,11.77-21.19,0-38.85-18.84-38.85-40C0,257.83,14.13,244.88,27.08,239l103.6-44.74L27.08,148.34C13,142.46,0,129.51,0,111.85,0,90.66,18.84,73,40,73c10.6,0,17.66,3.53,28.25,11.77l88.3,64.75L144.81,44.74C141.28,20,157.76,0,181.31,0s40,18.84,36.5,43.56L206,149.52l88.3-64.75C304.93,76.53,313.17,73,323.77,73a39.2,39.2,0,0,1,38.85,38.85c0,18.84-12.95,30.61-27.08,36.5L231.93,194.26,335.54,239c14.13,5.88,27.08,18.83,27.08,37.67,0,21.19-18.84,38.85-40,38.85-9.42,0-17.66-4.71-28.26-11.77L206,239l11.77,104.78c3.53,24.72-12.95,44.74-36.5,44.74s-40-18.84-36.5-43.56Z"></path>
</svg>
You are taking the worth contained in the d
attribute, paste it within the converter, and growth! You’ve gotten the next CSS:
.form {
aspect-ratio: 0.933;
clip-path: form(from 43.18% 61.52%,line by -24.35% 16.67%,curve by -8.12% 3.03% with -2.92% 1.82%/-5.2% 3.03%,curve by -10.71% -10.3% with -5.84% 0%/-10.71% -4.85%,curve to 7.47% 61.52% with 0% 66.36%/3.9% 63.03%,line by 28.57% -11.52%,line to 7.47% 38.18%,curve to 0% 28.79% with 3.59% 36.67%/0% 33.33%,curve to 11.03% 18.79% with 0% 23.33%/5.2% 18.79%,curve by 7.79% 3.03% with 2.92% 0%/4.87% 0.91%,line by 24.35% 16.67%,line to 39.93% 11.52%,curve to 50% 0% with 38.96% 5.15%/43.51% 0%,clean by 10.07% 11.21% with 11.03% 4.85%,line to 56.81% 38.48%,line by 24.35% -16.67%,curve to 89.29% 18.79% with 84.09% 19.7%/86.36% 18.79%,arc by 10.71% 10% of 10.81% 10.09% small cw,curve by -7.47% 9.39% with 0% 4.85%/-3.57% 7.88%,line to 63.96% 50%,line to 92.53% 61.52%,curve by 7.47% 9.7% with 3.9% 1.51%/7.47% 4.85%,curve by -11.03% 10% with 0% 5.45%/-5.2% 10%,curve by -7.79% -3.03% with -2.6% 0%/-4.87% -1.21%,line to 56.81% 61.52%,line by 3.25% 26.97%,curve by -10.07% 11.52% with 0.97% 6.36%/-3.57% 11.52%,clean by -10.07% -11.21% with -11.03% -4.85%,shut);
}
Observe that you just don’t want to supply any viewBox
information. The converter will routinely discover the smallest rectangle for the form and can calculate the coordinates of the factors accordingly. No extra viewBox
complications and no must combat with overflow or further spacing!
Right here is one other instance the place I’m making use of the form to a picture aspect. I’m conserving the unique SVG so you’ll be able to examine each shapes.
form()
When to make use of I’d be tempted to say “on a regular basis” however in actuality, not. In my information, I distinguish between two forms of shapes: Those with solely straight traces and those with curves. Every kind can both have repetition or not. Ultimately, we’ve 4 classes of shapes.

If we don’t have curves and we don’t have repetition (the simplest case), then clip-path: polygon()
ought to do the job. If we’ve a repetition (with or with out curves), then masks
is the best way to go. With masks
, we are able to depend on gradients that may have a selected dimension and repeat, however with clip-path
we don’t have such choices.
When you’ve got curves and don’t have a repetition, the brand new form()
is the best choice. Beforehand, we needed to depend on masks
since clip-path
could be very restricted, however that’s now not the case. After all, these will not be common guidelines, however my very own option to establish which choice is essentially the most appropriate. On the finish of the day, it’s at all times a case-by-case foundation as we could produce other issues to think about, such because the complexity of the code, the pliability of the strategy, browser help, and so on.
Let’s draw some shapes!
Sufficient speaking, let’s transfer to the fascinating half: drawing shapes. I cannot write a tutorial to clarify the “advanced” syntax of form()
. Will probably be boring and never fascinating. As an alternative, we’ll draw some frequent shapes and study by observe!
Rectangle
Take the next polygon:
clip-path: polygon(
0 0,
100% 0,
100% 100%,
0 100%
);
Technically, this may do nothing since it can draw a rectangle that already follows the aspect form which is a rectangle, nevertheless it’s nonetheless the right start line for us.
Now, let’s write it utilizing form()
.
clip-path: form(
from 0 0,
line to 100% 0,
line to 100% 100%,
line to 0 100%
);
The code must be self-explanatory and we have already got two instructions. The from
command is at all times the primary command and is used solely as soon as. It merely specifies the start line. Then we’ve the line
command that attracts a line to the following level. Nothing advanced to date.
We will nonetheless write it in a different way like under:
clip-path: form(
from 0 0,
hline to 100%,
vline to 100%,
hline to 0
);
Between the factors 0 0
and 100% 0
, solely the primary worth is altering which suggests we’re drawing a horizontal line from 0 0
to 100% 0
, therefore the usage of hline to 100%
the place you solely must specify the horizontal offset. It’s the identical logic utilizing vline
the place we draw a vertical line between 100% 0
and 100% 100%
.
I received’t advise you to attract your form utilizing hline
and vline
as a result of they are often difficult and are a bit tough to learn. All the time begin through the use of line
after which if you wish to optimize your code you’ll be able to exchange them with hline
or vline
when relevant.
We have now our first form and we all know the instructions to attract straight traces:
Round Minimize-Out
Now, let’s attempt to add a round cut-out on the prime of our form:

For this, we’re going to depend on the arc
command, so let’s perceive the way it works.

If we’ve two factors, A and B, there are precisely two circles with a given radius that intersect with each factors like proven within the determine. The intersection provides us 4 attainable arcs we are able to draw between factors A and B. Every arc is outlined by a dimension and a path.
There’s additionally the actual case the place the radius is the same as half the space between A and B. On this case, solely two arcs might be drawn and the path will resolve which one.

The syntax will appear like this:
clip-path: form(
from Xa Ya,
arc to Xb Yb of R [large or small] [cw or ccw]
);
Let’s add this to our earlier form. No want to consider the values. As an alternative, let’s use random ones and see what occurs:
clip-path: form(
from 0 0,
arc to 40% 0 of 50px,
line to 100% 0,
line to 100% 100%,
line to 0 100%
);
Not unhealthy, we are able to already see the arc between 0 0
and 40% 0
. Discover how I didn’t outline the scale and path of the arc. By default, the browser will use small
and ccw
.
Let’s explicitly outline the scale and path to see the 4 completely different circumstances:
Hmm, it’s working for the primary two blocks however not the opposite ones. Fairly unusual, proper?
Truly, every part is working fantastic. The arcs are drawn outdoors the aspect space so nothing is seen. In the event you add some box-shadow
, you’ll be able to see them:
Arcs might be difficult as a result of dimension and path factor, so get able to be confused. If that occurs, bear in mind that you’ve got 4 completely different circumstances, and making an attempt all of them will enable you to discover which one you want.
Now let’s attempt to be correct and draw half a circle with a selected radius positioned on the middle:

We will outline the radius as a variable and use what we’ve discovered to date:
.form {
--r: 50px;
clip-path: form(
from 0 0,
line to calc(50% - var(--r)) 0,
arc to calc(50% + var(--r)) 0 of var(--r),
line to 100% 0,
line to 100% 100%,
line to 0 100%
);
}
It’s working fantastic, however the code can nonetheless be optimized. We will exchange all of the line
instructions with hline
and vline
like under:
.form {
--r: 50px;
clip-path: form(from 0 0,
hline to calc(50% - var(--r)),
arc to calc(50% + var(--r)) 0 of var(--r),
hline to 100%,
vline to 100%,
hline to 0
);
}
We will additionally exchange the radius with 1%
:
.form {
--r: 50px;
clip-path: form(from 0 0,
hline to calc(50% - var(--r)),
arc to calc(50% + var(--r)) 0 of 1%,
hline to 100%,
vline to 100%,
hline to 0
);
}
While you outline a small radius (smaller than half the space between each factors), no circle can meet the situation we defined earlier (an intersection with each factors), so we can not draw an arc. This case falls inside an error dealing with the place the browser will scale the radius till we are able to have a circle that meets the situation. As an alternative of contemplating this case as invalid, the browser will repair “our mistake” and draw an arc.
This error dealing with is fairly cool because it permits us to simplify our form()
operate. As an alternative of specifying the precise radius, I merely put a small worth and the browser will do the job for me. This trick solely works when the arc we need to draw is half a circle. Don’t attempt to apply it with any arc
command as a result of it received’t at all times work.
One other optimization is to replace the next:
arc to calc(50% + var(--r)) 0 of 1%,
…with this:
arc by calc(2 * var(--r)) 0 of 1%,
Virtually all of the instructions can both use a to
directive or a by
directive. The primary one defines absolute coordinates just like the one we use with polygon()
. It’s the precise place of the purpose we’re transferring to. The second defines relative coordinates which suggests we have to take into account the earlier level to establish the coordinates of the following level.
In our case, we’re telling the arc to think about the earlier level (50% - R) 0
and transfer by 2*R 0
, so the ultimate level shall be (50% - R + 2R) (0 + 0)
, which is identical as (50% + R) 0
.
.form {
--r: 50px;
clip-path: form(from 0 0,
hline to calc(50% - var(--r)),
arc by calc(2 * var(--r)) 0 of 1px,
hline to 100%,
vline to 100%,
hline to 0
);
}
This final optimization is nice as a result of if we need to transfer the cutout from the middle, we solely must replace one worth: the 50%
.
.form {
--r: 50px;
--p: 40%;
clip-path: form(
from 0 0,
hline to calc(var(--p) - var(--r)),
arc by calc(2 * var(--r)) 0 of 1px,
hline to 100%,
vline to 100%,
hline to 0
);
}
How would you regulate the above to have the cut-out on the backside, left, or proper? That’s your first homework project! Attempt to do it earlier than transferring to the following half.
I’ll give my implementation as a way to examine with yours, however don’t cheat! If you are able to do this with out referring to my work, it is possible for you to to do extra advanced shapes extra simply.
Rounded Tab
Sufficient cut-out, let’s attempt to create a rounded tab:

Are you able to see the puzzle of this one? Much like the earlier form, it’s a bunch of arc
and line
instructions. Right here is the code:
.form {
--r: 26px;
clip-path: form(
/* left half */
from 0 100%,
arc by var(--r) calc(-1 * var(--r)) of var(--r),
vline to var(--r),
arc by var(--r) calc(-1 * var(--r)) of var(--r) cw,
/* proper half */
hline to calc(100% - 2 * var(--r)),
arc by var(--r) var(--r) of var(--r) cw,
vline to calc(100% - var(--r)),
arc by var(--r) var(--r) of var(--r)
);
}
It appears to be like a bit scary, however if you happen to observe it command by command, it turns into loads clearer to see what’s occurring. Here’s a determine that will help you visualize the left a part of it.

All of the arc
instructions are utilizing the by
directive as a result of, in all of the circumstances, I at all times want to maneuver by an offset equal to R, that means I don’t should calculate the coordinates of the factors. And don’t attempt to exchange the radius by 1%
as a result of it received’t work since we’re drawing 1 / 4 of a circle somewhat than half of a circle.
From this, we are able to simply obtain the left and proper variations:
Discover how I’m solely utilizing two arc
instructions as an alternative of three. One rounded nook might be performed with a basic border radius, so this might help us simplify the form.
Inverted Radius
One final form, the basic interior curve on the nook additionally known as an inverted radius. What number of arc
instructions do we want for this one? Verify the determine under and give it some thought.

In case your reply is six, you’ve got chosen the tough option to do it. It’s logical to consider six arcs since we’ve six curves, however three of them might be performed with a easy border radius, so solely three arcs are wanted. All the time take the time to research the form you’re creating. Typically, fundamental CSS properties might help with creating the form.
What are you ready for? That is your subsequent homework and I received’t enable you to with a determine this time. You’ve gotten all that you must simply create it. In case you are struggling, give the article one other learn and attempt to research the earlier shapes extra in depth.
Right here is my implementation of the 4 variations:
Conclusion
That’s all for this primary half. It is best to have overview of the form()
operate. We centered on the line
and arc
instructions that are sufficient to create many of the frequent shapes.
Don’t overlook to bookmark the SVG to CSS converter and regulate my CSS Form assortment the place you will discover the code of all of the shapes I create. And here’s a final form to finish this text.