curved cutout | by Karim Shalapi

An in-depth tutorial for this great functionality

Unsplash. Photo by Danny Gibe on

In many applications, we need a cutout from an element for stylistic reasons. Making cutouts is easy most of the time, but when it comes to curved cutouts, things start to get a little complicated because there’s no easy/straight way to do it, so let’s talk about it!

We will talk about a specific example and how to make it, but this does not mean that it is specific only to this shape. You can start drawing whatever shape you like using this technique hence the unlimited number of possible cutout shapes.

What we will be discussing today is how to make a curved cutout that looks like this:

curved cutout final result

We have two significant challenges that may prevent us from making this card.

curve challenge

As many of you may have already found out, the curves on the cutout will be the most challenging part as there are many curves attached in different ways – making it impossible to create such curves with a simple set of CSS rules Is.

dwindling issue

shadow challenge

if we use box-shadow This will cause us some problems because of the curved cutout, and it will look like this:

box shadow issue

This happens because the box shadow adds a shadow effect to your element’s frame. And the frame here, as we can see, doesn’t include the curve of our cutout.

The box-shadow CSS property adds a shadow effect around an element’s frame. You can set multiple effects separated by commas. A box shadow is described by the relative x and y offsets of the element, the blur and dispersion radii, and the color.
…read more — MDN Web Docs

Now that we know our challenges, we need to tackle them.

curve approach

As far as curves are concerned, we can approach this by creating an SVG that looks like this and using that as our background. The issue with this (in most cases) is that the SVG will have a fixed aspect ratio, which means it will distort if we try to apply any custom width and height to it. That said, it can be done with SVG, but we will not discuss that in this article.

Another way to deal with this problem is to use gradients.

stop! What? gradients?

Yes, some people think of gradients simply as a progressive transition between two or more colors, and between the colors of the gradient, there is a blurred mixture of the chosen colors. They are correct, but not completely.

<gradient> CSS data type is a special type <image> In which there is a progressive transition between two or more colors.
…read more — MDN Web Docs

In CSS gradients, you can define any color you want with any required opacity and place them at stop points, these stop points tell you where that color starts and ends in this gradient. Here are two tricks we can take advantage of:

  • We can stack stop points on each other to have a rigid line.
    How will this help? Well, if the stop points are further away from each other, this will create a spectrum of progressive colors between the two chosen colors, but if we stack the two stop points on top of each other, we will have two colors. There will be a hard line between , which means we can draw along these gradients.
    For example, if we want a circle, we can do a radial gradient with this trick, and it will draw a circle for use.
Gradient Stop Points Stacking
  • We can use any color with any opacity. This is huge because instead of having a gradient between two opaque colors, we can have a gradient between the desired and transparent colors. This will open up the possibility to make any shape we want and have a transparent background (this will all make sense when we start implementing it).
gradient between black and transparent

1. The tool used in the above GIF is
2. You can also use any CSS color keyword like
transparent which we will use in this tutorial, but feel free to use rgba() either hsla() works and sets alpha price to 0 Or play with its numbers as you like, or use any of your favorite CSS color functions.

shadow approach

fortunately, box-shadow Thanks to the widespread support of CSS, this issue is easily resolved nowadays filter Property.

Now, we can use drop-shadow() function in filter Property for adding content-aware shadows.

This means that it does not follow the frame of the element, but the outline of the content inside it. So, if we use a special kind of image forming gradient, as we mentioned earlier, then drop-shadow() The generated image will follow the outline. If this image has transparent parts, it will be considered by drop-shadow() function, unlike box-shadow Property.

box shadow vs drop shadow

drop-shadow() The CSS function applies a drop shadow effect to the input image. the result is a <filter-function>,
mdn web docs

We discussed what challenges we might face and how to deal with them, then there is nothing left but to apply it to make everything clear.

Knowing that we have such simple geometric figures to draw, such a curve must first be broken down into these simpler figures.

So, let’s start breaking it down into these shapes.

simple rounded corners

First, we see the curve at the other three corners.

3 simple rounded corners

We’ll ignore them from our procedure because they are simple enough to be called a . can be done with border-radius Property.

small circles

If we look closely, we’ll see two small circles that represent the upper left and lower right curves of the cutout.

small circles of cutouts

big circle cutout

Also, we can see that there is a big square with another big circle cutout from its corner.

large circles of cutouts

fill the boxes

Then we’ll quickly notice that we haven’t considered the top and right sides, so let’s add that in as well. Keep in mind that this couldn’t be done with just one box because if it were a box, it would hide the curve of the circle behind it, so we had to make two boxes extending to the edges and stopping at the center so that we could are still the curves of the circles.

cutout fill box

final division

So, the end result of splitting the larger shape into smaller, simpler shapes should look like this:

Final division result of cutout

Now that we’ve broken down the complex shape into simpler geometric shapes, we can finally start coding. So let’s start making these shapes one by one.

make big circle cutout

Here I’ll start with the most complicated shape of the bunch, in my opinion – the bigger circle cutout.

Fortunately, thanks to the tricks I mentioned earlier, with a little modification, we can create this shape with just one gradient.

So, how do we do this?

First, let’s create a simple gradient that should look something like this:

background: radial-gradient(
/* gradient shape */ circle,
/* first color */ transparent /* first color stop point */ 30px,
/* second color */ #fff /* second color stop point */ 31px

1. I’ll be using CSS variables to store values ​​that can be used again in the future, so from now on, you’ll be looking around in pen variables instead of plain numbers.

2. You will see me add 1px For any variable or number used in gradient stop points such as: calc(var(--circle-r) + 1px), This is because if the two stop points are exactly the same, the browser draws a jagged hard line that is not anti-aliased, so to solve this we use this addition trick 1px To add a bit of blur to every other stop point and to smooth the lines between the gradient colors.

We will focus on two things:

  1. The circle cutout is in the center.
  2. The white box takes up the full height and width of the element.

To fix this in radial gradients, we can specify where the center of the circle (where the gradient begins) can be by doing the following:

background: radial-gradient(
circle at /* x-position */ 100% /* y-position */ 0%,
transparent 30px,
#fff 31px

Here we’ll make a top-right cutout, so we’ll use 100% 0% values ​​to get it, but you can play with these numbers to get whatever position or curve you want, keeping in mind that these values ​​should not be % It can be any CSS unit of measurement.

Now take the large box with the circle cutout to leave room for the smaller circle and the fill box like we have shown earlier.

So, it should look something like this:

background:/* The gradient "special" image */ radial-gradient(
circle at 100% 0%,
transparent 30px,
#fff 31px
/* bg-image x-position */ 0px /* bg-image y-position */ 34px / /* bg-image width */ calc(100% - 34px) /* bg-image height */ 100% /* bg-image repeat-x */ no-repeat /* bg-image repeat-y */no-repeat

You can read more about the background shorthand property here.

Now, this big circle looks like the cutout we split earlier!

draw small circles

Now, it’s really easy to draw, we only need simple radial-gradient To draw two circles but get them in the right position, we’ll need to do some math (simple geometry).

do not fear; It’s simple math, but if you don’t like it, you can start playing with numbers until you hit something you like. I will explain how to put the circles in this position with a little math as it will save me some time.

Knowing that the space between two circle centers is the same as the space between the equal sides of two circles, we can calculate the space between the centers of smaller circles as follows:

space between small circles

space between circles circles-space Is equal to pillar-size And this big-circle-r,

So, we can apply this simple math equation like this:

--circles-space: calc(var(--big-circle-r) + var(--pillar-size));

pillar-size The big circle is the top and right inset of the cutout, this is the value we used to move the box down and to the left drawing a large circle cutout, pillar-size can never be less that small circle-r,

Now that we know the space between the circles, and we know they should be drawn to the edges, we can draw the circles as follows:

Note that to make a perfect circle, I wrote it like this:

background: radial-gradient(
circle closest-side,
var(--card-color) 100%,
transparent calc(100% + 1px)

we needed to add closest-side The logic of the radial gradient to calculate the percentage from the nearest side. You can read more about him here.

draw fill box

Now there are blank spaces in the result, they should be filled with fill box to finalize our drawing.

Note that in the fill box section above, it looked like the boxes were smaller at the top to fill in the blanks, but in the actual implementation, I’d like to make their height or width overlap with other components to be the full height or width respectively. I’ll take

This will prevent transparent lines from appearing between fill boxes and other components due to a fraction in position or size calculations.

Let’s now create simple boxes using linear-gradients in the respective places, as we did in the fill box section above.

final touch

Now the cards are starting to come together. But we are missing two things to finalize our design:

  1. simple rounded corners
  2. card shadow

Fortunately, it’s really easy to get these two points, because we can use the normal border-radius property to get rounded corners, and we can use drop-shadow() Works for shadows, as we discussed earlier in the shadow approach.

It should look something like this:

filter: drop-shadow(0 10px 48px rgba(21, 44, 115, 0.15));
border-radius: 50px 0 50px 50px;

We have worked with cards, which look exactly like the image. Also I made a colored version to show that the gradients draw the same shape as the one we made earlier.

We made a card with some complicated curved cutouts using gradients, and by dividing the curve into smaller shapes that could be drawn, we got to the final result.

After learning the tricks and methods I talked about in this article, you can use them to create any cutout shape or curve from any side or corner of the card.

In fact, you can go crazy with the design, draw whatever you want, and still have the background react dynamically with the height and width of your element without a fixed aspect ratio.


Leave a Comment