DEV Community

Cover image for Fully responsive CSS folded ribbon
Temani Afif for Playful Programming

Posted on Edited on

Fully responsive CSS folded ribbon

Find out more ribbon shapes here: css-generators.com/ribbon-shapes

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!

Code Structure:

<div class="container" data-ribbon="Ribbon content"></div>
🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini 🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini

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

.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;
}
🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini 🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini

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

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

Some geometry to understand the 29.29%

Ribbon CSS

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

  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 */
   );
🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini 🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini

CSS Ribbon

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

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.

.left::before {
  left:0;
  right:auto;
  transform: translate(-29.29%, -100%) rotate(-45deg);
  transform-origin: bottom right;
}
🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini 🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini

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

Top comments (1)

🔴 Live TV: this is learning/fully responsive css folded ribbon h - Pertandingan Hari Ini
 
sxdx profile image
René Koller •

To make this work in Safari (macOS and iOS) the composite mask needs to be changed to

-webkit-mask-composite: destination-in, xor;

See here: codepen.io/sxdx-the-looper/pen/Vwr...