An in-depth tutorial for this great functionality
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:
We have two significant challenges that may prevent us from making this card.
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.
if we use
box-shadow This will cause us some problems because of the curved cutout, and it will look like this:
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.
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.
- 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).
1. The tool used in the above GIF is https://cssgradient.io/
2. You can also use any CSS color keyword like
transparentwhich we will use in this tutorial, but feel free to use
hsla()works and sets
0Or play with its numbers as you like, or use any of your favorite CSS color functions.
box-shadow Thanks to the widespread support of CSS, this issue is easily resolved nowadays
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
drop-shadow()The CSS function applies a drop shadow effect to the input image. the result is a
, 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.
We’ll ignore them from our procedure because they are simple enough to be called a . can be done with
If we look closely, we’ll see two small circles that represent the upper left and lower right curves of the cutout.
big circle cutout
Also, we can see that there is a big square with another big circle cutout from its corner.
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.
So, the end result of splitting the larger shape into smaller, simpler shapes should look like this:
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:
/* 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
1pxFor 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
1pxTo 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:
- The circle cutout is in the center.
- 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:
circle at /* x-position */ 100% /* y-position */ 0%,
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%,
/* 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 circles
circles-space Is equal to
pillar-size And this
So, we can apply this simple math equation like this:
--circles-space: calc(var(--big-circle-r) + var(--pillar-size));
pillar-sizeThe 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-sizecan never be less that small
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:
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.
Now the cards are starting to come together. But we are missing two things to finalize our design:
- simple rounded corners
- 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.