Create a Swish CSS3 Folded Ribbon in Five Minutes



Take one line of markup, a couple of CSS3 rules (no images), and you can have yourself a swish folded ribbon effect in five minutes. Let's see how..
Step 1: Markup
We'll begin with an empty HTML document; doctype, charset declaration, head, body, the usual suspects. You'll also notice we're linking to the Google Web Fonts API so we can make use of the pleasantly decorative Montez typeface.
1 |
|
2 |
<!DOCTYPE html>
|
3 |
<html lang="en"> |
4 |
|
5 |
<head>
|
6 |
|
7 |
<meta charset="utf-8" /> |
8 |
|
9 |
<title>Swish CSS3 folded ribbon effect.</title> |
10 |
|
11 |
<link href='http://fonts.googleapis.com/css?family=Montez' rel='stylesheet' type='text/css'> |
12 |
|
13 |
</head>
|
14 |
|
15 |
<body>
|
16 |
|
17 |
</body>
|
18 |
|
19 |
</html>
|
Now we'll add our ribbon element. That's right, one element, that's all we need. In this case we're using an h1
header:
1 |
|
2 |
<!DOCTYPE html>
|
3 |
<html lang="en"> |
4 |
|
5 |
<head>
|
6 |
|
7 |
<meta charset="utf-8" /> |
8 |
|
9 |
<title>Swish CSS3 folded ribbon effect.</title> |
10 |
|
11 |
<link href='http://fonts.googleapis.com/css?family=Montez' rel='stylesheet' type='text/css'> |
12 |
|
13 |
</head>
|
14 |
|
15 |
<body>
|
16 |
|
17 |
<h1 class="ribbon">Swish CSS3 folded ribbon effect.</h1> |
18 |
|
19 |
</body>
|
20 |
|
21 |
</html>
|
Step 2: Stir in Some Style
Open up a new CSS file, link to it in the head
of your document, then jump into adding some styles.
1 |
|
2 |
html { |
3 |
background: url(black-linen.png); /* Black Linen http://subtlepatterns.com */ |
4 |
}
|
5 |
|
6 |
body { |
7 |
margin: 0; |
8 |
padding: 100px 0 0 0; |
9 |
}
|
10 |
|
11 |
.ribbon { |
12 |
padding: 0 25px; |
13 |
height: 80px; |
14 |
|
15 |
background: #c94700; |
16 |
color: #301607; |
17 |
|
18 |
position: relative; |
19 |
float: left; |
20 |
clear: left; |
21 |
|
22 |
font-family: 'Montez', cursive; |
23 |
font-size: 32px; |
24 |
line-height: 80px; |
25 |
text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.3); |
26 |
}
|
We've started by styling the html and the body, just for the purposes of the demo (and yes, I've used an image for the background, but the ribbon itself is 100% image free).
Then, we turn our attention to our ribbon element. We give it some padding left and right, but we're quite specific about the height (in this case 80px) as we'll need to replicate that for the folded-up end later. We also specify the line-height as 80px so that the text is centered vertically on the ribbon. We float and clear it left so that we can display several along the edge of the page if we want to.
Note: If, for whatever reason, you don't want to float your ribbon, give it a display: inline-block;
. This will cause it to be handled as an inline element (it won't fill up its parent), whilst at the same time behaving like a block-level element, allowing you to define width, height, padding, margins etc.



Looks nice enough already, eh?
Step 3: The Fold
We're going to add the fold by targeting the ever-popular :after
pseudo-selector. Here he is..
1 |
|
2 |
.ribbon:after { |
3 |
content: ""; |
4 |
display: block; |
5 |
width: 40px; |
6 |
height: 0px; |
7 |
|
8 |
position: absolute; |
9 |
right: 0; |
10 |
bottom: 0px; |
11 |
z-index: 20; |
12 |
|
13 |
border-bottom: 80px solid #de6625; |
14 |
border-right: 80px solid transparent; |
15 |
}
|



See it?
So what exactly is that odd blade-like thing we've just made, and how does it help us? It's a border, the bottom border of our :after
pseudo-element, which we've made 80px in thickness to match the height of our ribbon. We've sliced off the edge of it at 45° by defining the adjacent right-border and giving that a deliberate transparent background (not an uncommon trick). We've given it a width of 40px which determines the rectangular end. A diagram will make that clearer:



How our element is constructed
Step 4: Tables Turn
Having built our foldy-bit, we now need to pivot it on its end. To do that we're going to employ CSS3 transform properties and rotate it, like this:



Where would the world be without diagrams?
By default, applying a rotation to the element will spin it round a central axis - we need to turn it around its bottom right point, that's why we positioned it at the bottom right of the ribbon.
Here's the updated syntax, with a whole pile of vendor-specific rules to make sure all possible browsers are catered for:
1 |
highlight="41-50" |
2 |
.ribbon:after { |
3 |
content: ""; |
4 |
display: block; |
5 |
width: 40px; |
6 |
height: 0px; |
7 |
|
8 |
position: absolute; |
9 |
right: 0; |
10 |
bottom: 0px; |
11 |
z-index: 20; |
12 |
|
13 |
border-bottom: 80px solid #de6625; |
14 |
border-right: 80px solid transparent; |
15 |
|
16 |
-webkit-transform: rotate(90deg); |
17 |
-webkit-transform-origin: right bottom; |
18 |
-moz-transform: rotate(90deg); |
19 |
-moz-transform-origin: right bottom; |
20 |
-o-transform: rotate(90deg); |
21 |
-o-transform-origin: right bottom; |
22 |
-ms-transform: rotate(90deg); |
23 |
-ms-transform-origin: right bottom; |
24 |
transform: rotate(90deg); |
25 |
transform-origin: right bottom; |
26 |
}
|
Each transform:rotate
property twists our object 90°. Each transform-origin
property states that it's to be rotated around the bottom right point.
So, how's it looking?



Sweet!
We have ourselves a simple, yet effective ribbon, which will happily render in the following browsers:
- Firefox 3.5+
- Opera 10.5
- Safari 3.1+
- Chrome
- IE9
Anything below IE9 will currently come unstuck with the CSS3 transformations we've applied, but there is a workaround in the form of MS filters. I'm not going to delve into filters here, but if you need to cater for IE4 or above, then check out CSS3 Please! to see a neat example of them in action.
Step 5: Dark Shadows Falling
To add some dimension to the effect, let's place a shadow under the flap-thing (I still don't know what to call it).
It couldn't be easier, we'll use the :before
pseudo element of our ribbon and repeat more-or-less what we did for the :after
; create a black version of the shape, rotate it slightly less, and make sure (using z-index
) that it's placed under the original.
1 |
|
2 |
.ribbon:before { |
3 |
content: ""; |
4 |
display: block; |
5 |
width: 40px; |
6 |
height: 0px; |
7 |
|
8 |
position: absolute; |
9 |
right: 0; |
10 |
bottom: 0px; |
11 |
z-index: 10; |
12 |
|
13 |
border-bottom: 80px solid #000000; |
14 |
border-right: 80px solid transparent; |
15 |
|
16 |
-webkit-transform: rotate(80deg); |
17 |
-webkit-transform-origin: right bottom; |
18 |
-moz-transform: rotate(80deg); |
19 |
-moz-transform-origin: right bottom; |
20 |
-o-transform: rotate(80deg); |
21 |
-o-transform-origin: right bottom; |
22 |
-ms-transform: rotate(80deg); |
23 |
-ms-transform-origin: right bottom; |
24 |
transform: rotate(80deg); |
25 |
transform-origin: right bottom; |
26 |
}
|
Here's what we get:



Step 6: Subtle, Real Subtle
Probably best we tone down the effect of that shadow by shortening it and playing with its opacity.
1 |
|
2 |
.ribbon:before { |
3 |
content: ""; |
4 |
display: block; |
5 |
width: 20px; |
6 |
height: 0px; |
7 |
|
8 |
position: absolute; |
9 |
right: 0; |
10 |
bottom: 0px; |
11 |
z-index: 10; |
12 |
|
13 |
border-bottom: 80px solid rgba(0, 0, 0, 0.3); |
14 |
border-right: 80px solid transparent; |
We've swapped out the border color of #000000 for its RGBA equivalent, which (again) is fine for all aforementioned modern browsers including IE9. If you want to cater for earlier versions of IE then you'll once again need to apply the effect using MS filters. The following snippet is an example of doing so:
1 |
|
2 |
/* required to trigger hasLayout for IE 5, 6, 7 */
|
3 |
zoom: 1; |
4 |
|
5 |
/* and this makes the whole lot 30% opaque */
|
6 |
filter: alpha(opacity=30); |
Let's also add a similar drop-shadow to the ribbon itself..
1 |
|
2 |
.ribbon { |
3 |
padding: 0 25px; |
4 |
height: 80px; |
5 |
|
6 |
background: #c94700; |
7 |
color: #301607; |
8 |
|
9 |
position: relative; |
10 |
float: left; |
11 |
clear: left; |
12 |
|
13 |
font-family: 'Montez', cursive; |
14 |
font-size: 32px; |
15 |
line-height: 80px; |
16 |
text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.3); |
17 |
|
18 |
-moz-box-shadow: -7px 7px 0px rgba(0, 0, 0, 0.3); |
19 |
-webkit-box-shadow: -7px 7px 0px rgba(0, 0, 0, 0.3); |
20 |
box-shadow: -7px 7px 0px rgba(0, 0, 0, 0.3); |
21 |
}
|
..which gives us this:



Step 7: Highlight
We've built an effective ribbon and you may well want to use it just as it is. Before we call it a done deal, let's just look at a couple of additional touches.
1 |
|
2 |
.ribbon { |
3 |
padding: 0 25px; |
4 |
height: 80px; |
5 |
|
6 |
color: #301607; |
7 |
|
8 |
background-color: #c94700; |
9 |
background-image: -webkit-gradient(linear, left top, left bottom, from(#c94700), to(#b84100)); |
10 |
background-image: -webkit-linear-gradient(top, #c94700, #b84100); |
11 |
background-image: -moz-linear-gradient(top, #c94700, #b84100); |
12 |
background-image: -ms-linear-gradient(top, #c94700, #b84100); |
13 |
background-image: -o-linear-gradient(top, #c94700, #b84100); |
14 |
background-image: linear-gradient(top, #c94700, #b84100); |
15 |
|
16 |
border-bottom: 1px solid rgba(255, 255, 255, 0.3); |
Here we have a subtle gradient fill on the ribbon, complete with various vendor prefixes and the background-color
fallback for non-supporting (-IE10) browsers. We've also added a flash of highlight to the bottom of the ribbon with a light border.
1 |
|
2 |
.ribbon:after { |
3 |
content: ""; |
4 |
display: block; |
5 |
width: 40px; |
6 |
height: 0px; |
7 |
|
8 |
position: absolute; |
9 |
right: 0; |
10 |
bottom: -1px; |
11 |
z-index: 20; |
Having added a border, we've effectively made the ribbon 1px higher, so we need to bump the foldy-thing down a tad.



Step 8: Final Flourish
If you want to go really crazy, why not soften up the fold itself? It's easily done with an uneven rounded corner and a bit of positioning adjustment.
1 |
|
2 |
border-bottom-right-radius: 20px 5px; |
That's the rounded corner
1 |
|
2 |
bottom: 4px; |
1 |
|
2 |
bottom: 4px; |
And that's the foldy-bit, plus shadow, lifted slightly to account for the alteration.



A subtle, yet effective bend in the ribbon
Conclusion
That's it! There's nothing else to say - try it and let me know what you think. As always, thanks for following along!