Friday, April 3, 2026

Making Advanced CSS Shapes Utilizing form()


Creating rectangles, circles, and rounded rectangles is the fundamental of CSS. Creating extra complicated CSS shapes reminiscent of triangles, hexagons, stars, hearts, and so forth. is more difficult however nonetheless a easy process if we depend on fashionable options.

However what about these shapes having a little bit of randomness and lots of curves?

Quite a lot of names might apply right here: random wavy, wiggly, blob, squiggly, ragged, torn, and so forth. No matter you name them, all of us agree that they don’t seem to be trivial to create, they usually typically belong to the SVG world or are created with instruments and used as photos. Due to the brand new form() operate, we are able to now construct them utilizing CSS.

I received’t let you know they’re simple to create. They’re certainly a bit tough as they require quite a lot of math and calculation. For that reason, I constructed a number of turbines from which you’ll simply seize the code for the totally different shapes.

All it’s important to do is modify the settings and get the code very quickly. So simple as that!

Whereas most of it’s possible you’ll be tempted to bookmark the CSS turbines and depart this text, I counsel you to proceed studying. Having the turbines is sweet, however understanding the logic behind them is even higher. Chances are you’ll need to manually tweak the code to create extra form variations. We may even see a number of fascinating examples, so keep till the tip!

Discover: If you’re new to form(), I extremely suggest studying my 4-part sequence the place I clarify the fundamentals. It would aid you higher perceive what we’re doing right here.

How does it work?

Whereas most of the shapes you may create with my turbines look totally different, all of them depend on the identical approach: quite a lot of curve instructions. The primary trick is to make sure two adjoining curve create a clean curvature in order that the total form seems as one steady curve.

Here’s a determine of what one curve command can draw. I can be utilizing just one management level:

A normal curve with a control point in the very center. The second shows another curve with control point veering towards the left, contorting the curve.

Now, let’s put two curves subsequent to one another:

A wavy curve with two control points, one point up and the other down forming a wave along three points.

The ending level of the primary curve, E1, is the start line of the second curve, S2. That time is positioned inside the phase shaped by each the management factors C1 and C2. That’s the criterion for having an general clean curve. If we don’t have that, we get a discontinued “unhealthy” curve.

A wavy curve with two control points. The second point is moved down and toward the right, bending the curves second wav in an undesired way.

All we have now to do is to randomly generate totally different curves whereas respecting the earlier criterion between two consecutive curves. For the sake of simplicity, I’ll contemplate the widespread level between two curves to be the midpoint of the management factors to have much less randomness to take care of.

Creating the shapes

Let’s begin with the best form, a random wavy divider. A random curve on one facet.

A long blue rectangle with a jagged bottom edge.

Two variables will management the form: the granularity and the scale. The granularity defines what number of curves we may have (it is going to be an integer). The scale defines the house the place the curves can be drawn.

The same blue renctangle in two versions with two different jagged bottom edges, marked in red to show the shape. The first is labeled Granularity 8 and the second, with more and deeper jags, is labeled Granularity 18.

Step one is to create N factors and evenly place them on the backside of the aspect (N is the granularity).

A white rectangle with a black border and seven control points evenly spaced along the bottom edge.

Then, we randomly offset the vertical place of the factors utilizing the scale variable. Every level may have an offset equal to a random worth inside the vary [0 size].

A white rectangle with a black border and seven control points evenly spaced in a wavy formation along the bottom edge. A red label saying Size indicates the vertical height between the highest point and lowest point.

From there, we take two adjoining factors and outline their midpoint. We get extra factors.

A white rectangle with a black border and thirteen control points evenly spaced in a wavy formation along the bottom edge. A red label saying Size indicates the vertical height between the highest point and lowest point. Every even point is marked in blue.

Do you begin to see the thought? A primary set of factors is randomly positioned whereas a second set is positioned in a approach that meets the criterion we outlined beforehand. From there, we draw all of the curves, and we get our form.

The CSS code will appear like this:

.form {
  clip-path: form(from Px1 Py1,
    curve to Px2 Py2 with Cx1 Cy1,
    curve to Px3 Py3 with Cx2 Cy2,
    /* ... */
    curve to Pxi Pyi with Cx(i-1) Cy(i-1)
    /* ... */
  )
}

The Ci are the factors we randomly place (the management factors) and Pi are the midpoints.

From there, we apply the identical logic to the totally different sides to get totally different variation (backside, high, bottom-top, all sides, and so forth.).

A two-by-two grid of the same blue rectangle with different configurations of wavy edges. The first on the bottom, the second on the top, the third on the top and bottom, and the fourth all along the shape.

As for the blob, the logic is barely totally different. As an alternative of contemplating an oblong form and straight traces, we use a circle.

Two white circles with black borders that contain a smaller circle with a dashed border. The first circle has eight black control points around the outer circle evenly spaced. The second has 15 control points around it, even other one in blue and positioned between the outer and inner circles to form a wavy shape.

We evenly place the factors across the circle (the one shaped by the aspect if it has border-radius: 50%). Then, we randomly offset them nearer to the middle. Lastly, we add the midpoints and draw the form.

A large green blob shape.

We are able to nonetheless go fancier and mix the primary approach with the round one to think about a rectangle with rounded corners.

A blue rounded rectangle next to another version of itself with a large number of jagged edges all around it.

This was the trickiest one to implement as I needed to take care of every nook, all sides, and work with totally different granularities. Nonetheless, the consequence was fairly satisfying because it permits us to create rather a lot of fancy frames!

Present me the cool demos!

Sufficient concept, let’s see some cool examples and how you can merely use the turbines to create complex-looking shapes and animations.

We begin with a traditional format that includes quite a few wavy dividers!

We’ve got 4 shapes in that demo, and all of them are a easy copy/paste from the wavy divider generator. The header makes use of the underside configuration, the footer makes use of the highest configuration and the opposite components use the highest + backside configuration.

Let’s get fancy and add some animation.

Every aspect may have the next code:

@media display screen and (prefers-reduced-motion: no-preference) {
  .aspect {
    --s1: form( ... );
    --s2: form( ... );
    animation: dance linear 1.6s infinite alternate;
  }

  @keyframes dance {
    0% {clip-path: var(--s1)}
    to {clip-path: var(--s2)}
  }
}

From the generator, you repair the granularity and measurement, you then generate two totally different shapes for every one of many variables (--s1 and --s2). The variety of curves would be the similar, which suggests the browser can have an interpolation between each shapes, therefore we get a pleasant animation!

And what about introducing scroll-driven animation to have the animation primarily based on the scroll? All it’s important to do is add animation-timeline: scroll() and it’s performed.

Right here is identical impact with a sticky header.

For this one, you play with the scale. You repair the granularity and the form ID you then contemplate a measurement equal to 0 for the preliminary form (a rectangle) and a measurement totally different from 0 for the wavy one. Then you definately let the browser animate between each.

Do you see all the chances we have now? You possibly can both use the shapes as static decorations or create fancy animations between two (or extra) through the use of the identical granularity and adjusting the opposite settings (measurement and form ID).

What cool demo are you able to create utilizing these methods? Share it within the remark part.

I’ll depart you with extra examples you should use as inspiration.

A bouncing hover impact with blob shapes:

A squishy button with a hover and click on impact:

A wobbling body animation:

liquid reveal impact:

And a set of fancy CSS loaders yow will discover at my website.

Conclusion

Do you see all of the potential of the brand new form() operate? We now have the chance to create complex-looking shapes with out resorting to SVG or photos. Along with that, we are able to simply have good transition/animation.

Don’t neglect to bookmark my CSS Turbines web site, from the place you may get the code of the shapes we studied and extra. I even have the CSS Form web site which I’ll quickly replace to make the most of the brand new form() for many of the shapes and optimize quite a lot of outdated code!

What about you? Can you consider a fancy form we are able to create utilizing form()? Maybe you can provide me the thought for my subsequent generator!

Related Articles

Latest Articles