How to create a ribbon effect in CSS

When I was implementing the design for Hvad Bruges Pengene Til I figured it would be interesting to create the ribbon effect using pure CSS.

Turns out it was fairly easy as well, using CSS generated content.

Taking advantage of :before and :after pseudo elements, we can turn squeaky clean markup like

<h1 class="ribbon">Ribbon Rocks!</h1>


Check out the demo page

Show me the codes

The heavily commented CSS needed for this is:

.ribbon {
  background: #DD8888;
  /* This allows us to use absolute positioning inside the element */
  position: relative;
  /* Setting a width plus padding makes this element expand past the width of the containing element. */
  width: 100%;
  padding-left: 50px; /* 50px equals ribbon widths of 30px and article padding of 20px */
  padding-right: 50px;
  /* Negative margin positions the ribbon element outside the containing element, creating the illusion of wrapping around it. */
  margin-left: -50px;
/* These are the two ribbon "curls". The :before curl is placed to the left, :after to the right */
.ribbon:before, .ribbon:after {
  border-color: #444444;
  border-style: solid;
  border-width: 0;
  border-top-width: 15px; /* This sets the height of the curls, making it half the width to angle the curls more. */
  content: ''; /* Tells the browser to actually generate the pseudo element */
  position: absolute;
.ribbon:before {
  /* Position the :before element to the left and below the ribbon element */
  left: 0;
  bottom: -15px; /* Equal to the height of the curl */
  border-left: 30px solid transparent; /* Makes the curl slant right */
.ribbon:after {
  /* Position the :after element to the right and below the ribbon element */
  right: 0;
  bottom: -15px; /* Equal to the height of the curl */
  border-right: 30px solid transparent; /* Makes the curl slant left */

How it works

We basically turn the pseudo elements into two new block level elements, absolutely positioning them where we want the ribbon “curls” to show.

We then draw the curls using the borders of each element.

Browser support seems pretty good for this and it degrades nicely.

This isn’t a revolution by any stretch, neither am I the first to do it. But it is a pretty cool indication of what’s possible with generated content.