After the Heart Shape, let’s tackle another famous CSS shape; The Ribbon. I can hear you saying: “Why another article about CSS ribbon!?”. In this one, I will consider modern CSS tricks to create not one but a lot of ribbon shapes with the smallest code possible. In fact, the HTML code will be as simple as:
<div class="ribbon">I am a ribbon</div>
A single element is all that is needed to create different ribbon shapes. You can find all of them in one place and easily copy/paste the code: css-generators.com/ribbon-shapes
In this article, we will explore some of them to understand the CSS tricks used to create such shapes.
I will consider three categories for the ribbon: The full ribbon (the top one on the figure above), the ribbons on the corners, and the ones on the sides. The goal is to provide a CSS code that we can easily adjust to control the ribbon shape and also make sure the shape fits its content. We are not going to use any magic number of fixed dimensions. The size will be based on the text inside the ribbon.
The Full Ribbon
Let’s start with our first ribbon. Below is a figure to illustrate the different variables that will control the shape:
We define them using CSS variables
.ribbon {
--s: 50px; /* the ribbon size */
--d: 20px; /* the depth */
--c: 25px; /* the cutout part */
}
Now the trick is to rely on clip-path
and CSS gradients to build the shape. You are probably thinking we are going to use pseudo-elements and a lot of CSS code but no. Two properties will do the job.
We first apply the gradients:
background:
conic-gradient(at left var(--s) bottom var(--d),
#0000 25%,#0008 0 37.5%,#0004 0) 0 /50% no-repeat,
conic-gradient(at right var(--s) bottom var(--d),
#0004 62.5%,#0008 0 75%,#0000 0) 100%/50% no-repeat;
background-color: #CC333F
Each gradient covers half the area and is made with three different colors. A transparent one (#0000
) and two semi-transparent ones. By defining a background-color
behind the gradients we create the different shades of colors for our ribbon. Updating the color is as simple as changing the background-color
.
The last step is to apply the clip-path
. This will probably look a bit complex at first glance because the value is a bit verbose but if you follow the polygon point by point, it becomes easy.
.ribbon {
clip-path: polygon(0 var(--d), var(--s) var(--d),var(--s) 0,calc(100% - var(--s)) 0,calc(100% - var(--s)) var(--d),100% var(--d),calc(100% - var(--c)) calc(50% + var(--d)/2),100% 100%,calc(100% - var(--s) - var(--d)) 100%,calc(100% - var(--s) - var(--d)) calc(100% - var(--d)),calc(var(--s) + var(--d)) calc(100% - var(--d)),calc(var(--s) + var(--d)) 100%,0 100%,var(--c) calc(50% + var(--d)/2))
}
Here is a figure to illustrate some of the points.
You can refer to my article "CSS Tricks To Master The clip-path Property" to better understand the coordinates and how the shape's symmetry can help you easily find most of the values.
It’s done! We have a nice ribbon and all you have to do is update a few variables to easily control the shape:
.ribbon {
--s: 50px; /* the ribbon size */
--d: 20px; /* the depth */
--c: 20px; /* the cutout part */
padding: 0 calc(var(--s) + var(--d)) var(--d); /* we need some padding so the text doesn't overlap the ribbon part */
background:
conic-gradient(at left var(--s) bottom var(--d),
#0000 25%,#0008 0 37.5%,#0004 0) 0 /50% no-repeat,
conic-gradient(at right var(--s) bottom var(--d),
#0004 62.5%,#0008 0 75%,#0000 0) 100%/50% no-repeat;
clip-path: polygon(0 var(--d), var(--s) var(--d),var(--s) 0,calc(100% - var(--s)) 0,calc(100% - var(--s)) var(--d),100% var(--d),calc(100% - var(--c)) calc(50% + var(--d)/2),100% 100%,calc(100% - var(--s) - var(--d)) 100%,calc(100% - var(--s) - var(--d)) calc(100% - var(--d)),calc(var(--s) + var(--d)) calc(100% - var(--d)),calc(var(--s) + var(--d)) 100%,0 100%,var(--c) calc(50% + var(--d)/2));
background-color: #CC333F; /* the main color */
width: fit-content;
}
The Corner Ribbon
This ribbon shape is easier than the previous one because we have only one variable to control the shape and no complex gradient configuration.
We first define the background color and we apply a border at the bottom with a semi-transparent color to get a different shade from the main color and simulate the folded part.
.ribbon {
--f: 15px; /* control the folded part */
background: var(--c,#45ADA8);
border-bottom: var(--f) solid #0007;
}
Then we apply the clip-path
.ribbon {
clip-path: polygon(100% calc(100% - var(--f)),100% 100%,calc(100% - var(--f)) calc(100% - var(--f)),var(--f) calc(100% - var(--f)), 0 100%,0 calc(100% - var(--f)),999px calc(100% - var(--f) - 999px),calc(100% - 999px) calc(100% - var(--f) - 999px))
}
Most of the points should be easy to understand but two of them are a bit trick. the 999px calc(100% - var(--f) - 999px)
and calc(100% - 999px) calc(100% - var(--f) - 999px)
. I have to cut the shape of an isosceles triangle on each side but to do this I need to know the height of the element. I don't have this information since the height depends on the content and we don't want to set a fixed dimension.
The trick is to rely on a big value that should be bigger than any height we may encounter. I am using 999px
but it can be smaller since a ribbon won’t be that tall.
Finally, we rotate the ribbon either by 45deg
or -45deg
depending on the position we want. Such ribbon is generally placed on the corner of a container so in addition to the rotation we need to also consider some positioning to correctly place the ribbon:
.ribbon {
position: absolute;
top: 0;
}
.right {
right: 0;
transform: translate(calc((1 - cos(45deg))*100%), -100%) rotate(45deg);
transform-origin: 0% 100%; /* bottom left */
}
.left {
left: 0;
transform: translate(calc((cos(45deg) - 1)*100%), -100%) rotate(-45deg);
transform-origin: 100% 100%; /* bottom right */
}
Two more ribbon shapes straight into the collection!
The Side Ribbon
I suppose you get the main concept by now. All the ribbons use the same code structure and this one is not an exception.
We first apply a bottom border for the folded part and a left border to have enough space for the cutout. Then we use clip-path to create the final shape.
.ribbon {
--f: 15px; /* control the folded part*/
--r: 20px; /* control the ribbon shape */
position: absolute;
background: #FA6900;
border-bottom: var(--f) solid #0005;
border-left: var(--r) solid #0000;
clip-path:
polygon(0 0,100% 0,100% calc(100% - var(--f)),calc(100% - var(--f)) 100%,
calc(100% - var(--f)) calc(100% - var(--f)),0 calc(100% - var(--f)),
var(--r) calc(50% - var(--f)/2));
right: calc(-1*var(--f));
}
What about the other sides?
They follow the same idea with small updates to the code. In the above demo, I am showing the left side and the right side version but I let you try to figure out how to create the top side version. You can still find all of them here: css-generators.com/ribbon-shapes
Conclusion
Using clip-path
and a few CSS properties, we were able to create different kinds of ribbon shapes. We can easily control them by adjusting CSS variables not to mention that their size is defined by their content. You can even have multi-line of text and the ribbon will adjust accordingly.
Defining the clip-path
polygon is probably the trickiest part and it can be difficult to understand at first glance. Take the time to study each polygon of each example point by point and check my other article to learn more tricks around clip-path
. It also helps to use a pen and paper and draw them by hand.
Don’t forget that I made a collection of different ribbon shapes from where you can easily copy the code. This gives you more examples to study and get familiar with clip-path
and other properties.
Frequently Asked Questions
Are website builders easy to use?
One of the easiest ways to build a website is with a website builder. Using a website builder doesn't require any programming and coding skills.
Why should I create a website?
There are many reasons why you should create a website if you’re an artist. You can use it to create a place where people can learn about you, talk about your art, or show off your work.
Should I build my website with PHP?
PHP's flexibility and ease of integration with various databases like MySQL and PostgreSQL make it ideal for creating dynamic, data-driven websites.
Temani Afif is an expert web developer, a content creator, and a CSS addict. He is the mastermind behind CSS Loaders, CSS Generators, CSS Tip and a lot of CSS stuff.
View all posts by Temani Afif