Quantcast
Channel: CSS — SitePoint
Viewing all articles
Browse latest Browse all 15

How to Create CSS Ribbon Shapes with a Single Element

$
0
0

In this article, I’ll show you how to use modern CSS tricks to create fancy CSS ribbon shapes with minimal code. As an extra bonus, our ribbons will have hover animations!

CSS ribbons are everywhere, and you can find a ton of articles about them, but the ones we'll create here are a bit special. We’re going to rely on a single element to create each of the shapes, and CSS variables to easily control them. We aren’t going to rely on fixed dimensions or magic numbers. The shapes will fit their content so you don’t have to worry about the text inside.

I’ve made a collection of CSS ribbon shapes with a lot of cool examples, and in this article, we’re going to study two types of them, pictured below.

Folded ribbon and rotated ribbon

I'll be calling the left one the “folded ribbon” and the right one the “rotated ribbon”.

Creating a CSS Folded Ribbon Shape

The first step in creating our folded CSS ribbon is to define the variables of our shape.

Naming parts of our ribbon shape: r for the depth of the front arrow and end cutout, and s for the height of the fold

.ribbon {
  --r: 20px; /* control the cutout of the ribbon */
  --s: 20px; /* size of the folded part */
  --c: #d81a14;
}

Two variables will control the shape, and one variable will control the color.

Using clip-path to create a CSS ribbon

Now let’s move to the code. We're mainly going to rely on clip-path. The image below illustrates the polygon shape we're going to use.

The rectangle ribbon clipped at both ends

We add some padding to avoid cutting the text, then we apply the clip-path:

.ribbon {
  --r: 20px; /* control the cutout of the ribbon */
  --s: 20px; /* size of the folded part */
  --c: #d81a14;

  line-height: 1.6; /* control the height */
  padding-inline: 1.2lh calc(var(--r) + .2lh);
  background: var(--c);
  clip-path: polygon(1lh 0,100% 0,calc(100% - var(--r)) 50%,100% 100%,100% 100%, 0 100%,0 100%); 
}

Using the CSS lh unit

You may be wondering what’s going on with the lh unit. It’s a new unit that corresponds to the line-height value. Since we're using one line of text, the line-height setting is what controls the height, so 1lh is equivalent to the height of the element, which is super useful. (You can read more about the lh unit in An Overview of CSS Sizing Units.)

In clip-path, I need to cut the shape of an isosceles triangle, and to do this I need to know the height of the element. 1lh is equal to that height.

A corner triangle with sides measuring 1lh

Creating a CSS fold with clip-path

Now, to create the folded part, we're still going to use clip-path and update the previous polygon. The cool thing about clip-path is that it can cut “outside” the boundaries of the element. It may sound surprising or maybe useless, given that we have nothing outside, but it means we can include things like box-shadow, outline, pseudo-elements, and so on.

In our case, we'll rely on box-shadow. The image below illustrates the trick.

A half-circle shadow underneath the pointy end of the ribbon

Note how I'm updating the clip-path to include four new points, three of which are outside the element. Since the part we're cutting is outside, it’s not visible, but if we add a big box-shadow we make if visible. I've used a blue color to illustrate the idea above, but in the code we'll use the same color as the background:

.ribbon {
  --r: 20px; /* control the cutout of the ribbon */
  --s: 20px; /* size of the folded part */
  --c: #d81a14;

  line-height: 1.6; /* control the height */
  padding-inline: 1.2lh calc(var(--r) + .2lh);
  background: var(--c);
  clip-path: polygon(1lh 0,100% 0,calc(100% - var(--r)) 50%,100% 100%,1lh 100%,1lh calc(100% + var(--s)),.5lh calc(100% + var(--s) + var(--r)),0 calc(100% + var(--s)),0 100%);
  box-shadow: 0 0 0 999px var(--c); /* a big spread radius */
}

Finally, we add a touch of shadow effect by introducing a gradient and another box-shadow and we're done. Our CSS ribbon shape is perfect!

Working with polygons to invert our CSS ribbon

You're probably wondering how to create the second ribbon (the green one). We do the same thing but with a different polygon. We take the first polygon and we invert it.

A polygon can be written like so:

clip-path: polygon(X1 Y1, X2 Y2, ..., Xn Yn)

To get the opposite shape, you change all Xi by 100% - Xi. As simple as that! Before checking my code, try to do it alone using the polygon of the first ribbon.

How to animate our CSS ribbon

In the demo above, hover the shapes to notice a nice animation. To achieve it, we need to update the polygon on hover by offsetting some points. I won’t re-write the whole polygon on hover, but I will define a CSS variable that will control the offset.

If you focus on the animation, you'll notice that we have three points moving to the left and three points moving down and to the left as well.

Arrows showing the points of the polygon and the direction in which they move

We update the Xi of the points moving to left with Xi + d and we update the Yi of the points moving doing with Yi + d. Then we simply update the variable d to control the movement:

.ribbon {
  --d: 0px; /* This will control the offset */
  clip-path: polygon(calc(1lh + var(--d)) 0,100% 0,calc(100% - var(--r)) 50%,100% 100%,calc(1lh + var(--d)) 100%,calc(1lh + var(--d)) calc(100% + var(--s) + var(--d)),calc(.5lh + var(--d)) calc(100% + var(--s) + var(--r) + var(--d)),var(--d) calc(100% + var(--s) + var(--d)),var(--d) 100%);
}
.ribbon:hover {
  --d: .2lh;
}

If you see such a polygon for the first time, you may get confused, as it looks a bit scary. But in reality, it’s not that complex. We started with a simple polygon and we slowly added more points and more calculations until we reached this complex one.

The post How to Create CSS Ribbon Shapes with a Single Element appeared first on SitePoint.


Viewing all articles
Browse latest Browse all 15

Trending Articles