By Craig Buckler

How to Create CSS3 Paper Curls Without Images

By Craig Buckler

In my previous posts, we discovered how to create speech bubbles and ribbons without additional HTML elements or images. They were achieved using CSS3 effects applied to the :before and :after pseudo-elements. In this post, we’ll use a similar technique to create a CSS3 paper curl effect.

Paper curls have been popular for a few years. The viewer sees a natural-looking slightly curved box but, in reality, it’s an optical illusion created by a shadow at the bottom of the element:

CSS paper curl

Until recently, you’d need to create the shadow as an image in Photoshop, Gimp or another graphics package. Ideally, it would be a 24-bit alpha transparent PNG which could be overlaid on any background — but that would cause issues in older browsrs.

Fortunately, CSS3 provides a great alternative with several benefits:

  • The effect works in modern browsers but won’t be applied in browsers which don’t support it.
  • The shadow can be overlaid on any background without requiring additional images.
  • The effect can be applied to elements of any size.
  • The code is reusable and uses far fewer bytes than an image-based shadow.
  • The shadow is easy to configure. You can change the color or depth with a few code tweaks.

First, let’s create our single HTML element:

<div class="box">My box</div>

and apply a little shading to the inside and outside:

	position: relative;
	width: 500px;
	padding: 50px;
	margin: 0 auto;
	background-color: #fff;
	-webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
	-moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
	box-shadow: 0 0 5px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);

CSS paper curl

We now need curl effects on the bottom left and right edges. This is achieved by creating two :before and :after pseudo-elements which are:

  1. rotated and skewed using CSS3 transforms (all the latest browsers support transforms with vendor prefixes)
  2. positioned at the bottom edge, and
  3. given a box shadow.

CSS paper curl

We can now move the elements behind the main box using z-index: -1. Therefore, just the edge of their shadow becomes visible:

CSS paper curl

The pseudo-element CSS code:

.box:before, .box:after
	position: absolute;
	width: 40%;
	height: 10px;
	content: ' ';
	left: 12px;
	bottom: 12px;
	background: transparent;
	-webkit-transform: skew(-5deg) rotate(-5deg);
	-moz-transform: skew(-5deg) rotate(-5deg);
	-ms-transform: skew(-5deg) rotate(-5deg);
	-o-transform: skew(-5deg) rotate(-5deg);
	transform: skew(-5deg) rotate(-5deg);
	-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
	-moz-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
	box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
	z-index: -1;

	left: auto;
	right: 12px;
	-webkit-transform: skew(5deg) rotate(5deg);
	-moz-transform: skew(5deg) rotate(5deg);
	-ms-transform: skew(5deg) rotate(5deg);
	-o-transform: skew(5deg) rotate(5deg);
	transform: skew(5deg) rotate(5deg);

That’s a lot of vendor-prefixed code to achieve an effect, but it requires fewer bytes and HTTP requests than a graphic.

Please see the demonstration page for an example. It works as expected in IE9, Firefox, Chrome, Safari and Opera. IE6, IE7 and IE8 degrade gracefully and will not show any shadow effects. All the CSS code is contained in the HTML source.

And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Learn CSS3.

Comments on this article are closed. Have a question about CSS3? Why not ask it on our forums?

  • CedarCreek

    Very cool!

  • Mike

    Nice work. Thanks for the no restriction. ~Cheers

  • Ben

    Nice! This is very similar to Nicolas Gallagher’s CSS drop-shadows without images tutorial. His demo page adds a few more useful examples too.

  • Ryan Hellyer

    Awesome idea. If I hadn’t read your article and simply seen the effect on a website, I would have assumed they were images.

  • Veeresh

    Nice work, but its not working in ie.
    plz provide the same code for ie also
    thanks in advance

    • DoubleBee

      It works as expected in IE9, Firefox, Chrome, Safari and Opera. IE6, IE7 and IE8 degrade gracefully and will not show any shadow effects. All the CSS code is contained in the HTML source.

  • I’ve received several tweets reporting that the original source of this technique was either at or Several others have adapted the idea such as (different effects) or joost.kiens (IE6/7/8 support with filters).

    Please leave links to similar resources or send them to me and I’ll write a follow-up article…

  • Nicolas Gallagher

    The joost.kiens example doesn’t include the unprefixed versions of CSS3 properties or function values. There is no IE 6/7 support because those browsers do not support CSS structural pseudo-elements. And there is no IE 8 support because that browser does not support CSS box-shadow or CSS transforms.

  • rdh

    Ok – that’s a really great use of CSS – as Ryan said above – had I seen it, I would’ve assumed an image. thanks!

  • Dan Owen

    Thanks for the fine work.
    I see either the top image or the second image in my test case, not the paper curl shadows. I used all values including the “z-index: -1;”. I am viewing this in a Drupal content page. When I inspect the element with Firebug the “:before” and “:after” pseudoclasses aren’t visible in the CSS, but they aren’t in the Firebug CSS code on your example page either. Your example looks exactly like it should. Any ideas?

    • I suspect there are conflicting styles in your CSS — especially if you’re using a third-party template. For example, perhaps a negative z-index is defined on

      Unfortunately, pseudo elements aren’t displayed in Firebug or Opera Dragonfly. However, you can examine them in Chrome’s Inspector.

      Please post a URL if you can.

      • Mariano Asselborn

        Hey, guys, ran into Dan’s problem too (coincidentally on Drupal too). The way I solved it is by adding an inner div inside the box div. The problem is that the :before and :after boxes aren’t going behind their containing parent, so adding an inner puts them “in between”, and they get covered :)

        To the above example I would add:

        .box .inner {
        padding: 50px;
        background-color: #fff;

        And take them out from the .box class.

  • deepika bairagi

    cool CSS coding…

  • Nick

    Great Article, however this dosen’t appear to work where the div element has the attribute overflow:hidden

    Im using the blueprint CSS framework and the container element has the overflow:hidden attribute on it, if I set overflow:visible the whole layout gets messed up and the contents of the site isnt contained in the container.

  • Jon

    Lots of cool stuff in CSS3, nice example and tutorial.

  • Vamshipuli

    very good advance css3

  • Nice.

    Any sense in converting skew and rotate into matrix instead? It’s simpler to learn what’s going on having separate declarations – and it’s great how this article has done so – but in terms of the final product all you’re actually doing is flipping one value:

    Left shadow: matrix(1,-0.09,0,1,0,0) and
    Right shadow: matrix(1,0.09,0,1,0,0)

    Those are, of course, rounded values. Viewing “computed style” will show you how this takes place. It’s nice to see just how changing x to -x can reverse a transform. Browsers don’t operate in skew/rotate shorthand once they render transforms, and this can be problematic for animation using JavaScript… assuming you’d even want to. I’ve foolishly created something like this before when probably should’ve tried to go a more SVG-ish/Raphael.js way. Oops!

    • Thanks Josh – that’s a great idea.

      Matrices are a more difficult to understand and develop but, if you can leap that hurdle, they use less code and have other benefits.

Get the latest in Front-end, once a week, for free.