Fully responsive CSS folded ribbon
Tags: css, webdev, tutorial, codepen
Published: 2021-02-25 12:04:48

In this post, We will create a fully responsive ribbon with no hardcoded width or height. The size and position will dynamically adjust based on the content and we are not going to use a ton of HTML or JS. Only CSS!

{% codepen https://codepen.io/t_afif/pen/bGBaKWo %}

## Code Structure:

```html
<div class="container" data-ribbon="Ribbon content"></div>
```

Yes, only one `div` with the ribbon content as a data attribute.


```css
.container {
  --d:6px;  /* folded part */
  --c:blue; /* color */
  --f:16px; /* ribbon font-size */
  position: relative;
}
.container::before {
  content: attr(data-ribbon);
  font-size:var(--f);
  /* I : position & coloration */
  position: absolute;
  top: 0;
  right: 0;
  transform: translate(29.29%, -100%) rotate(45deg);
  transform-origin: bottom left;
  padding: 5px 35px calc(var(--d) + 5px);
  background: linear-gradient(rgba(0,0,0,0.5) 0 0) bottom/100% var(--d) no-repeat var(--c);
  /* II : clipping */
  clip-path: polygon(0 0,100% 0,100% 100%,calc(100% - var(--d)) calc(100% - var(--d)),var(--d) calc(100% - var(--d)) , 0 100%);
  /* III : masking */
  -webkit-mask: 
      linear-gradient( 135deg, transparent calc(50% - var(--d)*0.707),#fff 0) bottom left,
      linear-gradient(-135deg, transparent calc(50% - var(--d)*0.707),#fff 0) bottom right;
  -webkit-mask-size:300vmax 300vmax;
  -webkit-mask-composite: destination-in;
   mask-composite: intersect;
}
```

#### position & coloration

We color our element using two layers. The main color and a black overlay to the bottom for the folded part. Then we place it in the top right corner.


![Ribbon CSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1b5llfxvk1dx288xovbu.png)

Now we apply a transformation to have the correct placement and the magic of the responsiveness is here (yes it's the `29.29%` value)

![Ribbon CSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/si35iao87x0j3w8e0q1u.png)

Some geometry to understand the `29.29%`

![Ribbon CSS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8heujdr0y9oc8gf84t8x.png)

From the above we have the following formulas:

`cos(45deg) = a/w` where `w` is our element width

`x = w - a = w - w*cos(45deg) = w*(1-cos(45deg) = w*(1-0.70710678)`

So `x = 0,29289322*w ~ 29.29%`

####  clipping 

We will use `clip-path` to create the folded part at the bottom

```css
  clip-path: 
   polygon(
       0 0, /* a */
       100% 0, /* b */
       100% 100%, /* c */
       calc(100% - var(--d)) calc(100% - var(--d)), /* x */
       var(--d) calc(100% - var(--d)), /* y */
       0 100% /* d */
   );
```
![CSS Ribbon](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozr15ftjrcth0f1tinmx.png)

#### masking

The final touch is to cut the corners using two mask layers. The trick here is to consider a big square with a diagonal gradient inside and we cut at `50%` considering the folded part.

An illustration to explain for one corner:


![CSS Ribbon](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v74dmt6xwfcflnk5flgq.png)

We do the same for the other corner and we consider the intersection of both mask layers using `mask-composite: intersect`

## That's it!

Simply adjust the variables and the content to control the ribbon. We can easily move it to the left side by slightly adjusting the transformation and the position.

```css
.left::before {
  left:0;
  right:auto;
  transform: translate(-29.29%, -100%) rotate(-45deg);
  transform-origin: bottom right;
}
```

<sub>I am adding a transparent border and using background-clip to avoid some bad outline that will appear around the shape</sub>