Using CSS 2.1 pseudo-elements to provide up to 3 background canvases, 2 fixed-size presentational images, and multiple complex borders for a single HTML element. This method of progressive enhancement works for all browsers that support CSS 2.1 pseudo-elements and their positioning. No CSS3 support required.

Support: Firefox 3.5+, Safari 4+, Chrome 4+, Opera 10+, IE8+.

How does it work?

Essentially, you create pseudo-elements using CSS (:before and :after) and treat them similarly to how you would treat HTML elements nested within your target element. But they have distinct benefits – beyond semantics – over the use of nested HTML elements.

To provide multiple backgrounds and/or borders, the pseudo-elements are pushed behind the content layer and pinned to the desired points of the HTML element using absolute positioning.

The pseudo-elements contain no true content and are absolutely positioned. This means that they can be stretched to sit over any area of the “parent” element without affecting its content. This can be done using any combination of values for the top, right, bottom, left, width, and height properties and is the key to their flexibility.

What effects can be achieved?

Using just one element you can create parallax effects, multiple background colours, multiple background images, clipped background images, image replacement, expandable boxes using images for borders, fluid faux columns, images existing outside the box, the appearance of multiple borders, and other popular effects that usually require images and/or the use of presentational HTML. It is also possible to include 2 extra presentational images as generated content.

The Multiple Backgrounds with CSS 2.1 and Multiple Borders with CSS 2.1 demo pages show how several popular examples of these effects can be achieved with this technique.

Most structural elements will contain child elements. Therefore, more often than not, you will be able to gain a further 2 pseudo-elements to use in the presentation by generating them from the first child (and even last-child) element of the parent element. In addition, you can use style changes on :hover to produce complex interaction effects.

Example code: multiple background images

Using this technique it is possible to reproduce multiple-background parallax effects like those found on the Silverback site using just one HTML element.

The element gets its own background image and any desired padding. By relatively positioning the element it acts as the reference point when absolutely positioning the pseudo-elements. The positive z-index will allow for the correct z-axis positioning of the pseudo-elements.

#silverback {
  position: relative;
  z-index: 1;
  min-width: 200px;
  min-height: 200px;
  padding: 120px 200px 50px;
  background: #d3ff99 url(vines-back.png) -10% 0 repeat-x;

Both pseudo-elements are absolutely positioned and pinned to each side of the element. The z-index value of -1 moves the pseudo-elements behind the content layer. This way the pseudo-elements sit on top of the element’s background and border but all the content is still selectable or clickable.

#silverback:after {
  position: absolute;
  z-index: -1;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  padding-top: 100px;

Each pseudo-element then has a repeated background-image set. This is all that is needed to reproduce the parallax effect.

The content property lets you add an image as generated content. With two pseudo-elements you can add 2 further images to an element. They can be crudely positioned within the pseudo-element box by varying other properties such as text-align and padding.

#silverback:before {
  content: url(gorilla-1.png);
  padding-left: 3%;
  text-align: left;
  background: transparent url(vines-mid.png) 300% 0 repeat-x;

#silverback:after {
  content: url(gorilla-2.png);
  padding-right: 3%;
  text-align: right;
  background: transparent url(vines-front.png) 70% 0 repeat-x;

The finished product is part of the Multiple Backgrounds with CSS 2.1 demo.

Example code: fluid faux columns

Another application is creating equal height fluid columns without images or extra nested containers.

The HTML base is very simple. I’ve used specific classes on each child div rather than relying on CSS 2.1 selectors that IE6 does not support. If you don’t require IE6 support you don’t actually need the classes.

<div id="faux">
<div class="main">[content]</div>
<div class="supp1">[content]</div>
<div class="supp2">[content]</div>

The percentage-width container is once again relatively positioned and a positive z-index is set. Applying overflow:hidden gets the element to wrap its floated children and will hide the overflowing pseudo-elements. The background colour will provide the colour for one of the columns.

#faux {
  position: relative;
  z-index: 1;
  width: 80%;
  margin: 0 auto;
  overflow: hidden;
  background: #ffaf00;

By using relative positioning on the child div’s you can also control the order of the columns independently of their source order.

#faux div {
position: relative;
float: left;
width: 30%;

#faux .main { left: 35%; }
#faux .supp1 { left: -28.5%; }
#faux .supp2 { left: 8.5%; }

The other two full-height columns are produced by creating, sizing, and positioning pseudo-elements with backgrounds. These backgrounds can be (repeating) images if the design requires.

#faux:after {
   content: "";
   position: absolute;
   z-index: -1;
   top: 0;
   right: 0;
   bottom: 0;
   left: 33.333%;
   background: #f9b6ff;

#faux:after {
   left: 66.667%;
   background: #79daff;

The finished product is part of the Multiple Backgrounds with CSS 2.1 demo.

Example code: multiple borders

Multiple borders are produced in much the same way. Using them can avoid the need for images to produce simple effects.

An element must be relatively positioned and have sufficient padding to contain the width of the extra border you will be creating with pseudo-elements.

#borders {
   position: relative;
   z-index: 1;
   padding: 30px;
   border: 5px solid #f00;
   background: #ff9600;

The pseudo-elements are positioned at specific distances away from the edge of the element’s box, moved behind the content layer with the negative z-index, and given the border and background values you want.

#borders:before {
   content: "";
   position: absolute;
   z-index: -1;
   top: 5px;
   left: 5px;
   right: 5px;
   bottom: 5px;
   border: 5px solid #ffea00;
   background: #4aa929;

#borders:after {
   content: "";
   position: absolute;
   z-index: -1;
   top: 15px;
   left: 15px;
   right: 15px;
   bottom: 15px;
   border: 5px solid #00b4ff;
   background: #fff;

That’s all there is to it. The finished product is part of the Multiple Borders with CSS 2.1 demo.

Progressive enhancement and legacy browsers

IE6 and IE7 have no support for CSS 2.1 pseudo-elements and will ignore all :before and :after declarations. They get none of the enhancements but are left with the basic usable experience.

A warning about Firefox 3.0

Firefox 3.0 supports CSS 2.1 pseudo-elements but does not support their positioning. Due to this partial support, you should avoid declaring display:block for absolutely positioned pseudo-elements that explicitly declare a width or height values. However, when using borders there is no graceful fallback for Firefox 3.0. Although, sometimes an improved appearance in Firefox 3.0 can be achieved by adding display:block to pseudo-element hacks that use borders.

Enhancing with CSS3

All the applications included in this article could be further enhanced to take advantage of present-day CSS3 implementations.

Using border-radius, rgba, and transforms, and CSS3 multiple background images in tandem with pseudo-elements can produce even more complex presentations that I hope to include in a future article. Currently there is no browser support for the use of CSS3 transitions or animations on pseudo-elements.

In the future: CSS3 pseudo-elements

The proposed extensions to pseudo-elements in the CSS3 Generated and Replaced Content Module include the addition of nested pseudo-elements (::before::before), multiple pseudo-elements (::after(2)), wrapping pseudo-elements (::outside), and the ability to insert pseudo-elements into later parts of the document (::alternate).

These changes would provide a near limitless number, and arrangement, of pseudo-elements for all sorts of complex effects and presentations using just one element.

Let me know what you’ve done

I’ve focused on just a few applications and popular effects. If you find other applications, limitations, or want to share how you’ve applied this technique please leave a comment below or let me know on Twitter (@necolas.