Adding Vignettes to Images with CSS

Vignettes are something we've been able to add to images in Photoshop for many years - it describes the technique of reducing clarity towards the edges of images by reducing things like saturation and brightness, and can often give an image a different quality. It was for that reason that I decided I wanted to use them in my designs, but I certainly didn't want to use images that were pre-composed with the effect, and so decided it would be simple to add them using CSS. What I didn't know, was that there were many things conspiring to prevent me achieving the effect properly. So without further adieu, allow me to share my experience with you.

I first read Trent Walton's article on vignetting and implemented that on the site, but soon realised its shortcomings. Firstly the use of negative z-indexing played havoc with my backgrounds - this is because its fine if you have an all-white background, but if you have an image, it simply throws the picture behind it. And secondly I found myself frustrated with the fact that you couldn't right click and save the image with ease. I also took a look at Chris Coyier's article on the subject, but once again hit a brick wall.

So after a lot of playing around and many alterations I came up with a solution that is the combination of many techniques that I have come across, and the one use on the site today.

My HTML is as follows.

<figure>	
    <img src="path/to/image" alt="Test image" />
</figure>

The class of left simply floats the element to the left, while I use the following CSS to style the rest.

figure {
	position: relative;
	display: block; 
}

	figure.vignette img {
		z-index: 1;
		position: relative;
		display: block;
	}

	figure::before {
		content: "";
		position: absolute;
		top: -1em;
		bottom: -1em;
		left: -1em;
		right: -1em;
	}

	figure.vignette::after {
		position: absolute;
		top: 0;
		bottom: 0;
		left: 0;
		right: 0;
		content: "";
		z-index: 2;
		pointer-events: none;
		width:100%;
		height:100%;
		box-shadow:inset 0px 0px 85px rgba(0,0,0,.5);
		-webkit-box-shadow:inset 0px 0px 85px rgba(0,0,0,.5);
		-moz-box-shadow:inset 0px 0px 85px rgba(0,0,0,.5);
		border-radius: 3px;
		-moz-border-radius: 3px;
		-webkit-border-radius: 3px;
	}

So the main styling of the figure element simply makes sure it is visible and sets it's position to relative, as does the styling of the image within it; but it is the code that follows that does all the magic. We use the pseudo ::before and ::after to apply the vignette effect. If you are unfamiliar with those selectors, visit W3's article on the subject. You can increase the intensity of the vignette by altering the box-shadow property to have a less transparent shadow, or bigger radius. You could even have different colours by altering the same property.

And that's it! I haven't found any inherent problems with this technique just yet, and although this method isn't really apply a vignette in the traditional sense, I feel it does a pretty good imitation of it.

Using CSS Sprites

Navigation is an important part of how sites work, and so I think we can all agree that it is important for our navigational items to look nice. One problem that many sites encounter is the slow loading of roll-over images that are used to give feedback to the user. I'm sure you know what I'm talking about here - when you roll-over an image and it goes white for a moment before loading in the image? Well the reason for this problem is because the browser only loads the images that are going to be used immediately, and so when you're CSS uses something like #nav-item:hover { background-image:url(images/2.png) } to change the background image, the browser has to go off and find that image.

Ways of avoiding this are simple, and one of the best ways to do so is by using one image for all of your navigational images within one image! Sound crazy? Well that's what we call a sprite. Using CSS sprites will reduce your web-page's loading time and greatly reduce the number of requests made by the browser, and that can only be a good thing. Many sites use this method to ensure their servers don't die altogether, for example Apple uses it for their primary navigation.

Apple's Menu

So lets go ahead and create a nice looking menu.

We will begin with the HTML.

<div id="nav">
  <ul>
    <li id="menu-home"><a href="#">Home</a></li>
    <li id="menu-blog"><a href="#">Blog</a></li>
    <li id="menu-contacts"><a href="#">Contact</a></li>
    <li id="menu-about"><a href="#">About</a></li>
  </ul>
</div>

So that will just create for us a simple unordered list that we can now manipulate using the CSS below (and don't forget to link to your CSS file).

* {
	margin:0px;
	padding:0px;
}	

#nav {
	width:700px;
	height:55px;
	overflow:hidden;	
	padding-top:0px;
	margin-left:0px;
	margin-right:0px;
	display:block;
	list-style-type:none;
}

#nav li {
	list-style:none;	
	top:0px;
}

#nav a {
	display:block;
	width:150px;
	height:100px;
	background-image:url(images/blueMenu.png);
	text-indent:-9999px;
	float:left;
	margin:5px;
}

#menu-home a { background-position:0px 0px; }
#menu-home a:hover { background-position:0px -50px; }

#menu-blog a { background-position:-150px 0px; }
#menu-blog a:hover { background-position:-150px -50px; }

#menu-contact a { background-position:-300px 0px; }
#menu-contact a:hover { background-position:-300px -50px; }

#menu-about a { background-position:-450px 0px; }
#menu-about a:hover { background-position:-450px -50px; }

So together that HTML and the CSS will create a rather lovely menu. To customise the menu you will need to create your own image and aligning it up with the values in the CSS. To view a live example of this visit the demo page.

So what are the real benefits of this method? Well first off it will speed up your site, and although you might not recognise the speed increase straight-away, on sites where daily visits are in the 100s of thousands, the fewer HTTP requests, the better. Also there are the obvious benefits of using images as opposed to text, for example post pictures, and nice roll-over effects.

To finish I'd like to mention one drawback - if you want to edit only one menu item, you will have to have access to the original file to edit it, and then upload it to your server. This can be annoying if you are working on somebody else's site.

Oh and by the way, you don't have to just restrict yourself to menus, many of the larger sites such as YouTube use huge sprites to hold nearly all of the images on their site. Such an approach can be annoying if you are constantly editing your site, but the pros received on a large site are huge and will usually outweigh the cons.