Friday, October 17, 2025
HomeProgrammingHigher CSS Shapes Utilizing form() — Half 3: Curves

Higher CSS Shapes Utilizing form() — Half 3: Curves


Should you’re following alongside, that is the third submit in a sequence concerning the new CSS form() operate. We’ve discovered how to attract strains and arcs and, on this third half, I’ll introduce the curve command — the lacking command it is advisable know to have full management over the form() operate. In actuality, there are extra instructions, however you’ll not often want them and you may simply find out about them later by checking the documentation.

The curve command

This command provides a Bézier curve between two factors by specifying management factors. We are able to both have one management level and create a Quadratic curve or two management factors and create a Cubic curve.

Bézier, Quadratic, Cubic, management factors? What?!

For a lot of of you, that definition is just unclear, and even ineffective! You’ll be able to spend a couple of minutes studying about Bézier curves however is it actually price it? Most likely not, until your job is to create shapes all of the day and you’ve got a strong background in geometry.

We have already got cubic-bezier() as an easing operate for animations however, truthfully, who actually understands the way it works? We both depend on a generator to get the code or we learn a “boring” clarification that we neglect in two minutes. (I’ve one proper right here by the best way!)

Don’t fear, this text is not going to be boring as I’ll principally deal with sensible examples and extra exactly the use case of rounding the corners of irregular shapes. Here’s a determine for example a couple of examples of Bézier curves.

Comparing two curved lines, one with one control point and one with two control points.

The blue dots are the beginning and ending factors (let’s name them A and B) and the black dots are the management factors. And spot how the curve is tangent to the dashed strains illustrated in purple.

On this article, I’ll take into account just one management level. The syntax will observe this sample:

clip-path: form(
  from Xa Ya, 
  curve to Xb Yb with Xc Yc
);

arc command vs. curve command

We already noticed in Half 1 and Half 2 that the arc command is helpful establishing rounded edges and corners, however it is not going to cowl all of the instances. That’s why you will have the curve command. The tough half is to know when to make use of each and the reply is “it relies upon.” There is no such thing as a generic rule however my recommendation is to first see if it’s doable (and straightforward) utilizing arc. If not, then you must use curve.

For some shapes, we are able to have the identical consequence utilizing each instructions and this can be a good start line for us to grasp the curve command and evaluate it with arc.

Take the next instance:

That is the code for the primary form:

.form {
  clip-path: form(from 0 0,
    arc to 100% 100% of 100% cw,
    line to 0 100%)
}

And for the second, we’ve this:

.form {
  clip-path: form(from 0 0,
    curve to 100% 100% with 100% 0,
    line to 0 100%)
}

The arc command wants a radius (100% on this case), however the curve command wants a management level (which is 100% 0 on this instance).

Two rounded shapes that appear to have similar curves, one using an arc and another using a curve.

Now, for those who look intently, you’ll discover that each outcomes aren’t precisely the identical. The primary form utilizing the arc command is creating 1 / 4 of a circle, whereas the form utilizing the curve command is barely completely different. Should you place each of them above one another, you’ll be able to clearly see the distinction.

That is attention-grabbing as a result of it means we are able to spherical some corners utilizing both an arc or a curve, however with barely completely different outcomes. Which one is best, you ask? I might say it depends upon your visible choice and the form you might be creating.

In Half 1, we created rounded tabs utilizing the arc command, however we are able to additionally create them with curve.

Can you notice the distinction? It’s barely seen however it’s there.

Discover how I’m utilizing the by directive the identical method I’m doing with arc, however this time we’ve the management level, which can also be relative. This half could be complicated, so pay shut consideration to this subsequent bit.

Think about the next:

form(from Xa Ya, curve by Xb Yb with Xc Yc)

It implies that each (Xb,Yb) and (Xc,Yc) are relative coordinates calculated from the coordinate of the start line. The equal of the above utilizing a to directive is that this:

form(from Xa Ya, curve to (Xa + Xb) (Ya + Yb) with (Xa + Xc) (Yb + Yc))

We are able to change the reference of the management level by including a from directive. We are able to both use begin (the default worth), finish, or origin.

form(from Xa Ya, curve by Xb Yb with Xc Yc from finish)

The above implies that the management level will now take into account the ending level as an alternative of the start line. The result’s just like:

form(from Xa Ya, curve to (Xa + Xb) (Ya + Yb) with (Xa + Xb + Xc) (Ya + Yb + Yc))

Should you use origin, the reference would be the origin, therefore the coordinate of the management level turns into absolute as an alternative of relative.

The from directive could add some complexity to the code and the calculation, so don’t trouble your self with it. Merely understand it exists in case you face it, however maintain utilizing the default worth.

I feel it’s time to your first homework! Just like the rounded tab train, attempt to create the inverted radius form we lined within the Half 1 utilizing curve as an alternative of arc. Listed below are each variations so that you can reference, however attempt to do it with out peeking first, for those who can.

Let’s draw extra shapes!

Now that we’ve a superb overview of the curve command, let’s take into account extra advanced shapes the place arc gained’t assist us around the corners and the one answer is to attract curves as an alternative. Contemplating that every form is exclusive, so I’ll deal with the method fairly than the code itself.

Slanted edge

Let’s begin with an oblong form with a slanted edge.

A slanted rectangle shape in two stages, first with sharp edges, then with curved edges.

Getting the form on the left is kind of easy, however the form on the precise is a bit tough. We are able to spherical two corners with a easy border-radius, however for the slanted edge, we are going to use form() and two curve instructions.

Step one is to write down the code of the form with out rounded corners (the left one) which is fairly simple since we’re solely working with the line command:

.form {
  --s: 90px;  /* slant measurement */

  clip-path: 
    form(from 0 0,
    line to calc(100% - var(--s)) 0,
    line to 100% 100%,
    line to 0 100%
    );
}

Then we take every nook and attempt to spherical it by modifying the code. Here’s a determine for example the method I’m going to make use of for every nook.

Diagrammiong a rounded rectangular shape in three stages, first with sharp edges, then with points indicating where the curve control points are, then the completed shape.

We outline a distance, R, that controls the radius. From either side of the nook level, I transfer by that distance to create two new factors, that are illustrated above in purple. Then, I draw my curve utilizing the brand new factors as beginning and ending factors. The nook level would be the management level.

The code turns into:

.form {
  --s: 90px;  /* slant measurement */

  clip-path: 
    form(from 0 0,
    Line  to Xa Ya,
    curve to Xb Yb with calc(100% - var(--s)) 0,
    line to 100% 100%,
    line to 0 100%
    );
}

Discover how the curve is utilizing the coordinates of the nook level within the with directive, and we’ve two new factors, A and B.

Till now, the method is just not that advanced. For every nook level, you exchange the line command with line + curve instructions the place the curve command reuses the outdated level in its with directive.

If we apply the identical logic to the opposite nook, we get the next:

.form {
  --s: 90px;  /* slant measurement */

  clip-path: 
    form(from 0 0,
    line  to Xa Ya, 
    curve to Xb Yb with calc(100% - var(--s)) 0,
    line  to Xc Yc,
    curve to Xd Yd with 100% 100%,
    line to 0 100%
    );
}

Now we have to calculate the coordinates of the brand new factors. And right here comes the tough half as a result of it’s not at all times easy and it could require some advanced calculation. Even when I element this case, the logic gained’t be the identical for the opposite shapes we’re making, so I’ll skip the mathematics half and provide the ultimate code:

.field {
  --h: 200px; /* aspect peak */
  --s: 90px;  /* slant measurement */
  --r: 20px;  /* radius */
  
  peak: var(--h);
  border-radius: var(--r) 0 0 var(--r);
  --_a: atan2(var(--s), var(--h));
  clip-path: 
    form(from 0 0,
    line  to calc(100% - var(--s) - var(--r)) 0,
    curve by calc(var(--r) * (1 + sin(var(--_a)))) 
              calc(var(--r) * cos(var(--_a)))
    with var(--r) 0,
    line  to calc(100% - var(--r) * sin(var(--_a))) 
              calc(100% - var(--r) * cos(var(--_a))),
    curve to calc(100% - var(--r)) 100%  with 100% 100%,
    line to 0 100%
    );
}

I do know the code appears to be like a bit scary, however the excellent news is that the code can also be very easy to manage utilizing CSS variables. So, even when the mathematics is just not simple to understand, you don’t need to take care of it. It ought to be famous that I must know the peak to have the ability to calculate the coordinates which suggests the answer isn’t good as a result of the peak is a set worth.

Arrow-shaped field

Right here’s an analogous form, however this time we’ve three corners to spherical utilizing the curve command.

The ultimate code continues to be advanced however I adopted the identical steps. I began with this:

.form {
  --s: 90px; 

  clip-path: 
    form(from 0 0,
    /* nook #1 */
    line to calc(100% - var(--s)) 0,
    /* nook #2 */
    line to 100% 50%,
    /* nook #3 */
    line to calc(100% - var(--s)) 100%,

    line to 0 100%
    );
}

Then, I modified it into this:

.form {
  --s: 90px; 

  clip-path: 
    form(from 0 0,
    /* nook #1 */
    line  to Xa Ya
    curve to Xb Yb with calc(100% - var(--s)) 0,
    /* nook #2 */
    line  to Xa Ya
    curve to Xb Yb with 100% 50%,
    /* nook #3 */
    line  to Xa Yb
    curve to Xb Yb with calc(100% - var(--s)) 100%,

    line to 0 100%
    );
}

Lastly, I take advantage of a pen and paper to do all of the calculations.

You would possibly assume this method is ineffective if you’re not good with math and geometry, proper? Probably not, as a result of you’ll be able to nonetheless seize the code and use it simply because it’s optimized utilizing CSS variables. Plus, you aren’t obligated to be tremendous correct and exact. You’ll be able to depend on the above method and use trial and error to approximate the coordinates. It’s going to in all probability take you much less time than doing all the mathematics.

Rounded polygons

I do know you might be ready for this, proper? Due to the brand new form() and the curve command, we are able to now have rounded polygon shapes!

Three rounded polygon shapes, first a pentagon, second a triangle, and third an octagon.

Right here is my implementation utilizing Sass the place you’ll be able to management the radius, variety of sides and the rotation of the form:

If we omit the advanced geometry half, the loop is kind of easy because it depends on the identical method with a line + curve per nook.

$n: 9; /* variety of sides*/
$r: .2; /* management the radius [0 1] */
$a: 15deg; /* management the rotation */

.poly {
  aspect-ratio: 1;
  $m: ();
  @for $i from 0 by way of ($n - 1) {
    $m: append($m, line  to Xai Yai, comma);
    $m: append($m, curve to Xbi Ybi with Xci Yci, comma);
  } 
  clip-path: form(#{$m});
}

Right here is one other implementation the place I outline the variables in CSS as an alternative of Sass:

Having the variables in CSS is fairly helpful particularly if you wish to have some animations. Right here is an instance of a cool hover impact utilized to hexagon shapes:

I’ve additionally up to date my on-line generator so as to add the radius parameter. If you’re not accustomed to Sass, you’ll be able to simply copy the CSS code from there. Additionally, you will discover the border-only and cut-out variations!

A rounded shape with six sides next to a cutout of a rounded shape with six edges.

Conclusion

Are we executed with the curve command? Most likely not, however we’ve a superb overview of its potential and all of the advanced shapes we are able to construct with it. As for the code, I do know that we’ve reached a degree that’s not simple for everybody. I may have prolonged the reason by explicitly breaking down the mathematics, however then this text could be overly advanced and make it look like utilizing form() is tougher than it’s.

This mentioned, a lot of the shapes I code can be found inside my on-line assortment that I continuously replace and optimize so you’ll be able to simply seize the code of any form!

If you need a superb follow-up to this text, I wrote an article for Frontend Masters the place you’ll be able to create blob shapes utilizing the curve command.

Three blob shapes in a single row, each colored with a gradient that goes left to right from dark orange to light orange.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments