Wrap-around ribbons with CSS

Wrap-around ribbons with CSS

Now with semantic code

A while ago, back in 2010 when I was an innocent wee-little CSS newbie, I wrote a piece about creating a ribbon header with 'pure' CSS3, with what I thought was some pretty good code. That article got tweeted by @smashingmag, which generated a lot of traffic to my humble little site. It didn't take long before visitors started to point out better ways of achieving the same effect. Only now, finally, am I writing about the more semantic method of creating CSS ribbons.

Ribbons with CSS

Nulla at nulla justo, eget luctus tortor. Nulla facilisi. Duis aliquet egestas purus in blandit. Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti.

The markup is super-simple.

<div class="ribbon">
    <h3>Header text</h3>
    <p>Body text</p>
</div>
The making of the CSS ribbon

For the CSS, the header is given a width 10px wider than the box (1), and positioned relatively with a negative margin to the left to centre it (2). The triangles that make up the wrap-around ribbon are psuedo ::before and ::after elements, positioned absolutely (3). The rest of the CSS is just for looks.

/* vendor prefixes removed for clarity */
.ribbon {
    width: 350px;
    margin: 10px auto;
    padding: 0 10px 0;
    position: relative;
    color: #444;
    background: #fff;
    border: 1px solid #d2d2d2;
    border-radius: 3px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.ribbon h3 {
    display: block;
    height: 30px;
    line-height: 1.3;
    width: 360px;
    margin: 0;
    padding: 5px 10px;
    position: relative;
    left: -16px;
    top: 8px;
    color: #cfcfcf;
    text-shadow: 0 1px 1px #111;
    border-top: 1px solid #363636;
    border-bottom: 1px solid #202020;
    background: #333;
    background: linear-gradient(top, #383838 0%, #262626 100%);
    border-radius: 2px 2px 0 0;
    box-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
.ribbon h3::before,
.ribbon h3::after {
    content: '';
    display: block;
    width: 0;
    height: 0;
    position: absolute;
    bottom: -11px;
    z-index: -10;
    border: 5px solid;
    border-color: #242424 transparent transparent transparent;    
}
.ribbon h3::before {left: 0;}
.ribbon h3::after {right: 0;}

One thing to watch out for is the z-index - the pseudo elements are given a negative value so that they appear behind the containing box (which needs to have a background defined, else they will still be visible behind it). Depending on your existing CSS, the negative z-index could make the triangles disappear behind another element.

Replacing the triangles with circles can give a more rounded ribbon. A subtle gradient across the circle aids in the effect of the ribbon wrapping around the box.

Rounded CSS Ribbon

Nulla at nulla justo, eget luctus tortor. Nulla facilisi. Duis aliquet egestas purus in blandit. Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti.

/* Round */
.ribbon.round h3 {
    border-radius: 4px;
}
.ribbon.round h3::before,
.ribbon.round h3::after {
    width: 10px;
    height: 10px;
    bottom: -4px;
    border: none;
    border-radius: 10px;
}
.ribbon.round h3::before {
    background: #33aaf8;
    background: linear-gradient(left, #33aaf8 0%, #0674bb 100%);
}
.ribbon.round h3::after {
    background: #33aaf8;
    background: linear-gradient(right, #33aaf8 0%, #0674bb 100%);
}

Browser Support

The ribbons work fine in the latest versions of Safari, Chrome, Firefox and Opera. I haven't tested them in IE.

Enjoy the article? Tweet it!

tags — 3d css ribbon

Discussion - 15 comments

tsangk avatar

Anonymoustsangk 24 Mar 2012 06:06

And yup, this also works in IE 10:

bmccreative-ie10-02.PNG
bmccreative-ie10-03.PNG

Edit

Anonymous avatar

Bram van der VeenAnonymousAnonymous 17 Jun 2012 12:31

Awesome, Let's take a look if I can use this is my future works, im a CSS newbie myself :)

Edit

Anonymous avatar

mikalAnonymousAnonymous 11 Jul 2012 14:04

Nice work here but I can't seem to change the banner color

Edit

Anonymous avatar

mikalAnonymousAnonymous 11 Jul 2012 14:18

Never mind on that last comment duh. Thanks for the code.

Edit

RobElliott avatar

AnonymousRobElliott 26 Aug 2012 16:12

Although you have done this as a ribbon, it's also possible to do this on a Wikidot top bar menu.

ribbon-half.jpg

This example is at http://vineyard.wikidot.com

The CSS is:

#top-bar:before, #top-bar:after {
    bottom: -24px;
    content: "";
    display: block;
    position: absolute;
    z-index: -10;
}

#top-bar:before {
    border-color: transparent #444 transparent transparent;
    border-style: solid;
    border-width: 0 22px 25px 0;
    height: 0;
    left: -1px;
    width: 0;
}

#top-bar:after {
    border-color: #444 transparent transparent;
    border-style: solid;
    border-width: 25px 22px 0 0;
    height: 0;
    right: -1px;
    width: 0;
}

Edit

RobElliott avatar

AnonymousRobElliott 27 Aug 2012 19:58

The image above is now at http://plone4.wikidot.com

Edit

Anonymous avatar

TroyAnonymousAnonymous 26 Sep 2012 20:29

Excellent Ribbon Box: 1 Question, can this box scroll it's content; have a fixed height and a scroll bar on the right? I would appreciate the help..

Edit

Anonymous avatar

sAnonymousAnonymous 10 Sep 2013 16:33

sd

Edit

Anonymous avatar

jkatebinAnonymousAnonymous 06 Feb 2014 23:48

Nice! I'm starting out in CSS too, I made a few mod's to your code:
1) Repeated it for header levels 1-6
2) (most important imo) Removed the hard-coded width restrictions. Tried messing with percentages, padding, margins and such but never got a workable result. Ended up just using jQuery (call it in my main _layout page so if I use these ribbons on any other page it automatically resizes them.

I'm new to jquery too, so I'm sure this can be improved. As a coder, I hate using the 'copy-paste multiple times' type approach I've used below. Surely there's some way to just do a range (h1-h7) in a single css/query statement?

jquery:
$(function () {
//
// Resize all the ribbon header elements to match their div's
//
$(".ribbon h1").each(function (e) { $(this).width($(this).closest(".ribbon").width() + 12); });
$(".ribbon h2").each(function (e) { $(this).width($(this).closest(".ribbon").width() + 12); });
$(".ribbon h3").each(function (e) { $(this).width($(this).closest(".ribbon").width() + 12); });
$(".ribbon h4").each(function (e) { $(this).width($(this).closest(".ribbon").width() + 12); });
$(".ribbon h5").each(function (e) { $(this).width($(this).closest(".ribbon").width() + 12); });
$(".ribbon h6").each(function (e) { $(this).width($(this).closest(".ribbon").width() + 12); });
});

css:

.ribbon {
width: 100%;
margin: 10px auto;
padding: 0 10px 0;
position: relative;
color: #444;
background: #fff;
border: 1px solid #d2d2d2;
border-radius: 3px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

.ribbon h1, .ribbon h2, .ribbon h3, .ribbon h4, .ribbon h5, .ribbon h6, .ribbon h7 {
display: block;
line-height: 1.3;
margin: 0;
padding: 5px 10px;
position: relative;
left: -16px;
top: 8px;
color: #cfcfcf;
text-shadow: 0 1px 1px #111;
border-top: 1px solid #363636;
border-bottom: 1px solid #202020;
background: #333;
background: linear-gradient(top, #383838 0%, #262626 100%);
border-radius: 2px 2px 0 0;
box-shadow: 0 1px 2px rgba(0,0,0,0.3);
}

.ribbon h1::before, .ribbon h1::after, .ribbon h2::before, .ribbon h2::after, .ribbon h3::before, .ribbon h3::after, .ribbon h4::before, .ribbon h4::after, .ribbon h5::before, .ribbon h5::after, .ribbon h6::before, .ribbon h6::after {
content: '';
display: block;
width: 0;
height: 0;
position: absolute;
bottom: -11px;
z-index: -10;
border: 5px solid;
border-color: #242424 transparent transparent transparent;
}

.ribbon h1::before, .ribbon h2::before, .ribbon h3::before, .ribbon h4::before, .ribbon h5::before, .ribbon h6::before {
left: 0;
}

.ribbon h1::after, .ribbon h2::after, .ribbon h3::after, .ribbon h4::after, .ribbon h5::after, .ribbon h6::after {
right: 0;
}

.ribbon p {
margin: inherit;
}

Edit

Anonymous avatar

jkatebinAnonymousAnonymous 06 Feb 2014 23:52

And a 5 second google search later…

$(".ribbon :header").each(function (e) { $(this).width($(this).closest(".ribbon").width() + 12); });

Edit

Anonymous avatar

AshuGoelAnonymousAnonymous 21 May 2014 06:45

How to use rounded CSS with the mentioned div. Sorry, I am newbie in CSS. :)

Edit

Anonymous avatar

AnonymousAnonymous 14 Apr 2015 18:33

Edit

Anonymous avatar

AnonymousAnonymous 14 Apr 2015 18:33

Edit

Anonymous avatar

ashleyAnonymousAnonymous 21 Dec 2016 08:12

i want to apply this ribbon in my blogger dropdown menu and sidebar title , please help!

Edit

Anonymous avatar

Scott Johnson (@jwir3)AnonymousAnonymous 13 Mar 2017 02:02

I was having difficulty with this having weird z-index rendering when using as a popup "info" panel. To alleviate this, I removed "z-index: -10;" from h3:before, h3:after selector block, and added the following:

h3:before {
border-right: none;
}

h3:after {
border-left: none;
}

It simply doesn't render the left/right border components of the triangle, now, which is what I wanted.

Hope this helps someone in the future.

Edit

Add a new comment

Site design © BMC WebDesign, 2011. All rights reserved. All tutorials on this site are free for commerical use, subject to conditions outlined in the disclaimer.