Prepared for the second half? We’re nonetheless exploring the form()
perform, and extra exactly, the arc command. I hope you took the time to digest the primary half as a result of we are going to soar straight into creating extra shapes!
As a reminder, the form()
perform is barely supported in Chrome 137+ and Safari 18.4+ as I’m penning this in Might 2025.
Sector form
One other basic form that may also be utilized in pie-like charts.

It’s already clear that we’ve got one arc. As for the factors, we’ve got two factors that don’t transfer and one which strikes relying on how a lot the sector is stuffed.

The code will seem like this:
.sector {
--v: 35; /* [0 100]*/
aspect-ratio: 1;
clip-path: form(from prime, arc to X Y of R, line to heart);
}
We outline a variable that may management the filling of the sector. It has a price between 0
and 100
. To attract the form, we begin from the prime
, create an arc till the purpose (X, Y), after which we transfer to the heart
.
Are we allowed to make use of key phrase values like
prime
andheart
?
Sure! Not like the polygon()
perform, we’ve got key phrases for the actual circumstances similar to prime
, backside
, left
, and many others. It’s precisely like background-position
that method. I don’t suppose I have to element this half because it’s trivial, but it surely’s good to know as a result of it could possibly make your form a bit simpler to learn.
The radius of the arc ought to be equal to 50%
. We’re working with a sq. component and the sector, which is a portion of a circle, have to fill the entire component so the radius is the same as half the width (or top).1
As for the purpose, it’s positioned inside that circle, and its place will depend on the V worth. You don’t need a boring math clarification, proper? No want for it, right here is the system of X and Y:
X = 50% + 50% * sin(V * 3.6deg)
Y = 50% - 50% * cos(V * 3.6deg)
Our code turns into:
.sector {
--v: 35; /* [0 100] */
aspect-ratio: 1;
clip-path: form(from prime,
arc to calc(50% + 50% * sin(var(--v) * 3.6deg))
calc(50% - 50% * cos(var(--v) * 3.6deg)) of fifty%,
line to heart);
}
Hmm, the end result just isn’t good, however there aren’t any errors within the code. Can you determine what we’re lacking?
It’s the scale and path of the arc!
Keep in mind what I informed you within the final article? You’ll at all times have hassle with them, but when we strive the completely different mixtures, we will simply repair the difficulty. In our case, we have to use: small cw
.
Higher! Let’s strive it with extra values and see how the form behaves:
Oops, some values are good, however others not a lot. The path must be clockwise, however perhaps we must always use giant
as an alternative of small
? Let’s strive:
Nonetheless not working. The difficulty right here is that we’re shifting one level of the arc primarily based on the V worth, and this motion creates a unique configuration for the arc
command.
Right here is an interactive demo to raised visualize what is going on:
Whenever you replace the worth, discover how giant cw
at all times tries to observe the most important arc between the factors, whereas small cw
tries to observe the smallest one. When the worth is smaller than 50
, small cw
provides us a great end result. However when it’s greater than 50
, the giant cw
mixture is the great one.
I do know, it’s a bit difficult and I needed to review this explicit instance to emphasise the truth that we will have numerous complications working with arcs. However the extra points we face, the higher we get at fixing them.
The answer on this case is fairly easy. We hold using giant cw
and add a border-radius
to the component. When you examine the earlier demo, you’ll discover that even when giant cw
just isn’t producing a great end result, it’s filling the world we wish. All we have to do is clip the additional area and a easy border-radius: 50%
will do the job!
I’m holding the box-shadow
in there so we will see the arc, however we will clearly see how border-radius
is making a distinction on the primary form.
There’s nonetheless one edge case we have to contemplate. When the worth is the same as 100
, each factors of the arc may have the identical coordinates, which is logical for the reason that sector is full and we’ve got a circle. However when it’s the case, the arc will do nothing by definition and we received’t get a full circle.
To repair this, we will restrict the worth to, for instance, 99.99
to keep away from reaching 100
. It’s type of hacky, but it surely does the job.
.sector {
--v: 35; /* [0 100]*/
--_v: min(99.99, var(--v));
aspect-ratio: 1;
clip-path: form(from prime,
arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))
calc(50% - 50% * cos(var(--_v) * 3.6deg)) of fifty% giant cw,
line to heart);
border-radius: 50%;
}
Now our form is ideal! And don’t neglect which you can apply it to picture parts:
Arc form
Just like the sector form, we will additionally create an arc form. In any case, we’re working with the arc
command, so we’ve got to do it.

We have already got half the code because it’s mainly a sector form with out the inside half. We merely want so as to add extra instructions to chop the inside half.

.arc {
--v: 35;
--b: 30px;
--_v: min(99.99, var(--v));
aspect-ratio: 1;
clip-path: form(from prime,
arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))
calc(50% - 50% * cos(var(--_v) * 3.6deg)) of fifty% cw giant,
line to calc(50% + (50% - var(--b)) * sin(var(--_v) * 3.6deg))
calc(50% - (50% - var(--b)) * cos(var(--_v) * 3.6deg)),
arc to 50% var(--b) of calc(50% - var(--b)) giant
);
border-radius: 50%;
}
From the sector form, we take away the line to heart
piece and substitute it with one other line
command that strikes to some extent positioned on the inside circle. When you examine its coordinates with the earlier level, you will note an offset equal to --b
, which is a variable that defines the arc’s thickness. Then we draw an arc in the wrong way (ccw
) till the purpose 50% var(--b)
, which can also be a degree with an offset equal to --b
from the highest.
I’m not defining the path of the second arc since, by default, the browser will use ccw
.
Ah, the identical problem we hit with the sector form is hanging once more! Not all of the values are giving a great end result because of the identical logic we noticed earlier, and, as you possibly can see, border-radius
just isn’t fixing it. This time, we have to discover a option to conditionally change the scale of the arc primarily based on the worth. It ought to be giant
when V is greater than 50
, and small
in any other case.
Situations in CSS? Sure, it’s attainable! First, let’s convert the V worth like this:
--_f: spherical(down, var(--_v), 50)
The worth is throughout the vary [0 99.99]
(don’t neglect that we don’t need to attain the worth 100). We use spherical()
to verify it’s at all times equal to a a number of of a selected worth, which is 50
in our case. If the worth is smaller than 50
, the result’s 0
, in any other case it’s 50
.
There are solely two attainable values, so we will simply add a situation. If --_f
is the same as 0
we use small; in any other case, we use giant:
.arc {
--v: 35;
--b: 30px;
--_v: min(99.99, var(--v));
--_f: spherical(down,var(--_v), 50);
--_c: if(model(--_f: 0): small; else: giant);
clip-path: form(from prime,
arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))
calc(50% - 50% * cos(var(--_v) * 3.6deg)) of fifty% cw var(--_c),
line to calc(50% + (50% - var(--b)) * sin(var(--_v) * 3.6deg))
calc(50% - (50% - var(--b)) * cos(var(--_v) * 3.6deg)),
arc to 50% var(--b) of calc(50% - var(--b)) var(--_c)
);
}
I do know what you might be pondering, however let me let you know that the above code is legitimate. You in all probability don’t realize it but, however CSS has lately launched inline conditionals utilizing an if()
syntax. It’s nonetheless early to play with it, however we’ve got discovered an ideal use case for it. Here’s a demo which you can check utilizing Chrome Canary:
One other option to categorical situations is to depend on model queries which have higher assist:
.arc {
--v: 35;
--b: 30px;
--_v: min(99.99, var(--v));
--_f: spherical(down, var(--_v), 50);
aspect-ratio: 1;
container-name: arc;
}
.arc:earlier than {
content material: "";
clip-path: form(from prime,
arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))
calc(50% - 50% * cos(var(--_v) * 3.6deg)) of fifty% cw var(--_c, giant),
line to calc(50% + (50% - var(--b)) * sin(var(--_v) * 3.6deg))
calc(50% - (50% - var(--b)) * cos(var(--_v) * 3.6deg)),
arc to 50% var(--b) of calc(50% - var(--b)) var(--_c, giant)
);
@container model(--_f: 0) { --_c: small }
}
The logic is similar however, this characteristic requires a parent-child relation, which is why I’m utilizing a pseudo-element. By default, the scale will probably be giant
, and if the worth of --_f
is the same as 0
, we change to small
.
Notice that we’ve got to register the variable --_f
utilizing @property
to have the ability to both use the if()
perform or model queries.
Did you discover one other delicate change I’ve made to the form? I eliminated border-radius
and I utilized the conditional logic to the primary arc. Each have the identical problem, however border-radius
can repair solely one among them whereas the conditional logic can repair each, so we will optimize the code somewhat.
Arc form with rounded edges
What about including rounded edges to our arc? It’s higher, proper?

Are you able to see the way it’s accomplished? Take it as a small train and replace the code from the earlier examples so as to add these rounded edges. I hope you’ll be able to discover it by your self as a result of the modifications are fairly simple — we replace one line
command with an arc
command and we add one other arc
command on the finish.
clip-path: form(from prime,
arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))
calc(50% - 50% * cos(var(--_v) * 3.6deg)) of fifty% cw var(--_c, giant),
arc to calc(50% + (50% - var(--b)) * sin(var(--_v) * 3.6deg))
calc(50% - (50% - var(--b)) * cos(var(--_v) * 3.6deg)) of 1% cw,
arc to 50% var(--b) of calc(50% - var(--b)) var(--_c, giant),
arc to prime of 1% cw
);
If you don’t perceive the modifications, get out a pen and paper, then draw the form to raised see the 4 arcs we’re drawing. Beforehand, we had two arcs and two strains, however now we’re working with arcs as an alternative of strains.
And did you bear in mind the trick of utilizing a 1%
worth for the radius? The brand new arcs are half circles, so we will depend on that trick the place you specify a tiny radius and the browser will do the job for you and discover the right worth!
Conclusion
We’re accomplished — sufficient in regards to the arc
command! I needed to write two articles that concentrate on this command as a result of it’s the trickiest one, however I hope it’s now clear find out how to use it and find out how to deal with the path and measurement factor, as that’s in all probability the supply of most complications.
By the way in which, I’ve solely studied the case of round arcs as a result of, in actuality, we will specify two radii and draw elliptical ones, which is much more complicated. Until you need to develop into a form()
grasp, you’ll not often want elliptical arcs, so don’t trouble your self with them.
Till the following article, I wrote an article for Frontend Masters the place you possibly can create extra fancy shapes utilizing the arc
command that may be a good follow-up to this one.

In our case, we’ve got a sq. component so 50% of the direction-agnostic measurement will probably be equal to 50% of sqrt(Width² + Height²)/sqrt(2)
. And since each width and top are equal, we finish with 50% of the width (or the peak). ⮑