How to Build a jQuery Brush Stroke Navigation

by in Tutorials on 5th Feb 2010 · Comments

Today we are building an animated navigation for a watercolor-styled website which will have links that appear to be painted when it is hovered on. The watercolor graphics were created in Photoshop and we’ll be using the popular jQuery JavaScript framework for the animation.

jQuery Brush Stroke Navigation


Tutorial Demo

Before we go into the steps of building the jQuery Brush Stroke Navigation, you can check out the final tutorial demo below.

Final Tutorial

The Graphics – Photoshop

The background canvas is a pattern that comes with Photoshop (I’m using CS4 but I’m pretty sure that it was available in previous versions) and is grouped in the Greyscale Paper section. Some of the brushes that I’ve used to paint the background can be found in the Bittbox water color brush sets, vol. 1 and vol. II. The folks on NETTUTS recently released a free pack of brushes. There are a lot more brush sets to be found online and I bet you know what I’m going to say next; Google is your friend.

I just have a few tips on creating the brush strokes. First, make sure that you set the brush Spacing to a very low value, doing so will make the strokes continuous. You will find the Spacing slider under the Brush Tip Shape tab in the Brushes palette (if you can’t see it, call it by pressing F5).

Brushes Palette

In my example, I have six navigation elements and I have planned a 6 pixel margin between them. That means that I will have 930 pixels for the six elements. That’s 960px for the container DIV minus 30px for the margins between the items (five times 6 pixels). That gives us 155 pixels per item. I have used the white blocks you can see in the image below as a boundary for my strokes and then duplicated them to properly space out the navigation items.

Navigation Items

The Code

You can see the folder structure for our example in the image below. It is quite simple. A folder for images, another for script files, one HTML file and a CSS file.

Folders

The next two sections cover the HTML and CSS for the demo page.

The Content – HTML5

We’ll be using some HTML5 elements to build our demo page. The code will be based on the techniques described in the excellent Smashing Magazine article: Designing a HTML5 Layout from Scratch.

Here’s the complete code and then we’ll go over each part of it.

<!DOCTYPE HTML>
<html lang="en-US">
<head>
	<title>jQuery Nav Demo</title>
	<meta charset="UTF-8">
	<link rel="stylesheet" type="text/css" href="style.css" media="all">
	<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
	<!--[if lt IE 8]><script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE8.js" type="text/javascript"></script><![endif]-->
</head>
<body>
<header>
	<h1 id="logo">Fictive Company</h1>
	<nav class="clearfix"><ul>
		<li class="active fromLeft cssOnly"><a id="nHom" href="#"><span>Home</span></a></li>
		<li class="fromLeft cssOnly"><a id="nAbo" href="#"><span>About Us</span></a></li>
		<li class="fromTop cssOnly"><a id="nPro" href="#"><span>Products</span></a></li>
		<li class="fromBottom cssOnly"><a id="nNew" href="#"><span>News</span></a></li>
		<li class="fromRight cssOnly"><a id="nSer" href="#"><span>Services</span></a></li>
		<li class="inOut last cssOnly"><a id="nCon" href="#"><span>Contact Us</span></a></li>
	</ul></nav>
</header>

<script type="text/javascript" src="scripts/jquery-1.4.min.js"></script>
<script type="text/javascript" src="scripts/myScripts.js"></script>

</body>
</html>

First, let’s take a look at the HEAD element and you’ll notice that it’s preceded by very simple doctype and language declarations.

<!DOCTYPE HTML>
<html lang="en-US">
<head>
	<title>jQuery Nav Demo</title>
	<meta charset="UTF-8">
	<link rel="stylesheet" type="text/css" href="style.css" media="all">
	<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
	<!--[if lt IE 8]><script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE8.js" type="text/javascript"></script><![endif]-->
</head>

Now, inside the head tag, we have some standard tags; the title, a meta tag setting the character set, a link to our style sheet and a couple of JavaScript files inside of conditional comments. The first JS file is added to ensure proper HTML5 support in Internet Explorer (IE).

This script forces IE to properly style the elements it doesn’t recognize (like header, nav and other new HTML5 elements). The second script (IE8.js) adds advanced CSS features to older versions of Internet Explorer.

We move onto the body element and our unordered list:

<body>
<header>
	<h1 id="logo">Fictive Company</h1>
	<nav class="clearfix"><ul>
		<li class="active fromLeft cssOnly"><a id="nHom" href="#"><span>Home</span></a></li>
		<li class="fromLeft cssOnly"><a id="nAbo" href="#"><span>About Us</span></a></li>
		<li class="fromTop cssOnly"><a id="nPro" href="#"><span>Products</span></a></li>
		<li class="fromBottom cssOnly"><a id="nNew" href="#"><span>News</span></a></li>
		<li class="fromRight cssOnly"><a id="nSer" href="#"><span>Services</span></a></li>
		<li class="inOut last cssOnly"><a id="nCon" href="#"><span>Contact Us</span></a></li>
	</ul></nav>
</header>

After the body tag, we insert the header element. Our page only has the header in it, containing the logo and the navigation, but if it had more content, that content would go below the header element. First we have a H1 tag containing the logo. Following the logo is the nav element containing our navigation.

The navigation itself is coded as an unordered list. Each list item has a different class assigned to it so that we can easily target each one with jQuery. The idea is to show off a different effect for each list item. Each list item is also wrapped within span tags; more on this in the following CSS section.

Below is the look of our page without any styles applied:

No Style

The Content – CSS

As always, I start my CSS files with an edited version of Eric Meyer’s CSS Reset. After that, I’ve added the Clearfix hack, the new Jeff Star version.

/* Clearfix */
.clearfix:after {
	visibility: hidden;
	display: block;
	font-size: 0;
	content: " ";
	clear: both;
	height: 0;
}
* html .clearfix             { zoom: 1 } /* IE6 */
*:first-child+html .clearfix { zoom: 1 } /* IE7 */

header, nav { display: block } /* HTML5 tags */

The Clearfix hack is a really handy way of clearing floats; you can read more about it on Jeff’s site. The last line in the code above is added to improve HTML5 support, it tells the browsers to treat the header and nav elements as block level elements.

Moving on, we set the styles for the basic layout elements.

/* L A Y O U T */
html { background: #d5bd89 url(images/bgHtml.jpg) repeat }
body { background: url(images/bgBody.png) no-repeat top center }

/* HEADER */
header {
	width: 960px;
	margin: 0 auto;
	padding-top: 30px;
}

#logo {
	background: url(images/logo.png) no-repeat;
	width: 460px;
	height: 66px;
	text-indent: -9999px;
	display: block;
	margin: 0 0 25px 8px;
}

First, we set the background for the html element (our canvas pattern that repeats across the entire page). The background for the body element is our watercolor “artwork” that we’ve centered by background positioning. The header element is centered by setting the left and right margins to auto. This way we ensure that our content (in this case, our logo and navigation) is centered horizontally.

Normally, I would use a container class (although you may name it differently) to center my content and limit to the standard 960 pixels. But to keep things simple and short for the sake of this tutorial, I’ve styled the header element directly.

Finally, we use CSS image replacement to style our logo. We’re using the text-indent method. We set the background image for the element and push the HTML text within the h1 tags out of browser frame by setting a high negative text-indent value. This way we ensure that we only see the nice text in the image we’ve created in Photoshop.

Now comes the last part of our style sheet where we set the styles for the navigation unordered list.

/* Navigation */
ul li {
	display: inline-block;
	position: relative;
	float: left;
	margin: 0 6px 20px 0;
}
ul li a {
	background: url(images/bgNav.png) no-repeat;
	text-indent: -9999px;
	height: 80px;
	width: 155px;
	text-align: center;
	display: block;
	position: relative;
	float: left;
}
.last { margin-right: 0 }

We begin by floating all list items to the left and setting the margins. Next we style the links within the list items. We’re giving them a common background image because we’ve exported the entire navigation graphics from Photoshop as a single slice. We have to set the links as block level elements to be able to set their exact sizes and to be able to use the CSS image replacement method we’ve used for the logo.

I’ve added the last class to the last link (Contact Us) to make sure it doesn’t have a right margin of 6 pixels. Those 6 extra pixels would make the row 966 pixels wide and it would have to wrap to the next row because we’ve set our header element to be 960 pixels wide. Normally, we would use the last-child pseudo-class to set the last element’s margin to zero.

We would write something like this:

ul li:last-child { margin-right: 0 }

Unfortunately, some browsers don’t register this pseudo-class. It works in Google Chrome, Opera, Firefox and Internet Explorer 7, but IE8 and Safari wrap the last element to the next row. I believe that the HTML5 doctype is causing the problem. If anyone knows more regarding this problem, please share your knowledge in the comments.

We move on to positioning the background image for each of the navigation items:

#nHom { background-position: 0 0 }
#nAbo { background-position: -155px 0px }
#nPro { background-position: -310px 0px }
#nNew { background-position: -465px -80px }
#nSer { background-position: -620px -80px }
#nCon { background-position: -775px 0px }

Each of the items has an id set in the HTML markup and here we position our image containing all the graphics. The first value sets the horizontal starting position of the image; the second value sets the vertical. As we move through the items, we push the image to the left. The different vertical background position for the News and Services links will be explained in the next section when we start writing the jQuery code.

Below is the bit of CSS which styles the span elements which we’ll animate using jQuery.

ul li a span {
	background: url(images/bgNav.png) no-repeat;
	display: none;
	position: absolute;
	left: 0;
	top: 0;
	height: 80px;
	width: 155px;
}

#nHom span { background-position: 0 -80px }
#nAbo span { background-position: -155px -80px }
#nPro span { background-position: -310px -80px }
#nNew span { background-position: -465px 0px; display: block }
#nSer span { background-position: -620px 0px; display: block }
#nCon span { background-position: -775px -80px }

We have set the position of the span elements to absolute because we want them to appear directly on top of our links. That’s why we’ve set the left and top attributes to zero. We’ve also set the display attribute to none because we’ll animate them in with jQuery. The background position of the span elements differs from the corresponding links’ background position only in the vertical direction.

The last part of the CSS code below covers hover and active states of the links:

/* Hover States */
.cssOnly #nHom:hover { background-position: 0 -80px; }
.cssOnly #nAbo:hover { background-position: -155px -80px; }
.cssOnly #nPro:hover { background-position: -310px -80px; }
.cssOnly #nNew span:hover { background-position: -465px -80px; }
.cssOnly #nSer span:hover { background-position: -620px -80px; }
.cssOnly #nCon:hover { background-position: -775px -80px; }

/* Active State */
.active #nHom { background-position: 0 -160px; }

The cssOnly class that we’ve added to all li elements ensures that the background changes when we hover over the link, even if JavaScript is disabled in the browser.

Here is the final look of our page:

Final Look

The Code – jQuery

We’ve come to the main part of the tutorial. You were probably familiar with the techniques discussed in the HTML and CSS sections, but hopefully, this part will be new to you. At the end of our index.html file we call the myScripts.js script file located in the scripts folder. The first thing we’re going to do is to remove the cssOnly class from all list elements.

// If JS is disabled, CSS menu will still work
$(function() {
	$("li").removeClass("cssOnly");
});

This will remove the hover effect we’ve set in the CSS so that we’ll only see the effects animated with jQuery.

The first effect will be animating a brush stroke from left to right. All of the elements that have the fromLeft class will be animated with the code below:

//From the left
$(function() {
	$(".fromLeft a").hover(
		function(){
			$(this).find("span").stop(true, true).animate({ width: 'show' }, 1000);
		},
		function(){
			$(this).find("span").fadeOut(800);
	});
})

The first thing that we do here is to find the anchor tags that are nested within the elements that have the fromLeft class. When we hover over those, the function is executed:

$(this).find("span").stop(true, true).animate({ width: 'show' }, 1000);

The function finds the span element, which is the child element of the link we’re hovering over, and animates it. Before we start the animation, the stop tells the browser to stop other animations that may be in the queue. (Thanks to Liam and Diego for reminding me in the comments to add the stop function.)

The animate function has two arguments here. One is the width property which we’ll animate by setting it to show. We’ve set the display attribute of the span element to none in our CSS so the function sets it to block by animating its width over one thousand milliseconds (the second argument of the animate function), i.e. one second. Because we’re animating the width, the animation goes from left to right and we’ve achieved the illusion that the new color is painted on.

After closing the parenthesis, we enter a comma. Then we write a second function that animates the span when we mouse out from the link:

$(this).find("span").fadeOut(800);

This time it finds the span element and makes it fade out over 800 milliseconds. The next effect is a simple variation of the first one. We’re going to animate the span element so that it appears to be painted from the top down. The script looks for the links nested within elements having the fromTop class.

//From the top
$(function() {
	$(".fromTop a").hover(
		function(){
			$(this).find("span").stop(true, true).animate({ height: 'show' }, 1000);
		},
		function(){
			$(this).find("span").fadeOut(800);
	});
})

This function differs from the first one only in the property being animated; we’re now displaying the span element by animating its height. On mouse out, we fade out the span element.

For this next effect to be achieved, we have to make some changes in our styles. You’ll remember that the span elements nested within News and Services links had their display properties set to block. We’ve done that because the next two effects are basically the same as the first two effects, only reversed.

//From the right
$(function() {
	$(".fromRight a").hover(
		function(){
			$(this).find("span").stop(true, true).animate({ width: 'hide' }, 1000);
		},
		function(){
			$(this).find("span").fadeIn(800);
	});
})

For the brush stroke to be “applied” from right to left, we’re animating its width and setting it to hide. We’ve switched the backgrounds for the link and the span element in our CSS. The default state green-colored background is applied to the span, and the hover state yellow-colored background is applied to the link element. To show the default state on mouse out, we have to fade in the span element.

The next effect (from the bottom up) is similar to the previous one. This is basically a reversed version of the top down effect.

//From the bottom
$(function() {
	$(".fromBottom a").hover(
		function(){
			$(this).find("span").stop(true, true).animate({ height: 'hide' }, 1000);
		},
		function(){
			$(this).find("span").fadeIn(800);
	});
})

Because we have reversed backgrounds for the link and the span element, we animate the height by setting it to hide. This gives us the effect of an upward brush stroke. On mouse out, we fade in the span element.

This last effect is similar to the first one but it has a different mouse out effect:

//Slide IN-OUT
$(function() {
	$(".inOut a").hover(
		function(){
			$(this).find("span").stop(true, true).animate({ width: 'show' }, 1000);
		},
		function(){
			$(this).find("span").animate({ width: 'hide' }, 1000);
	});
})

On hover, the span is animated and we have a brush stroke from the left. By using hide to animate the width on mouse out, we achieve the effect of the original background color being painted on from the right.

As you can see, there are many combinations for this type of effects, and with different graphics, the number of possibilities is multiplied. Try creating your own graphics and experiment with the jQuery code; you’ll surely end up with some cool results. As always, if you run into any problems, you can post a comment here and I’ll try to help if I can.

Examples of jQuery Navigation Effects

Here are some very cool navigation effects that can be seen on the web.
Dragon Interactive
This is the amazing Dragon Interactive website. The navigation has a brilliant fade effect that draws you in. This is also one of the most copied effects and the subject of many tutorials that can be found on the web.

Dragon Interactive
Wilshire Investments
Like mentioned earlier, the Dragon Interactive navigation effect is often copied and this is my version of it. It was done for a company called Wilshire Investments.

Wilshire Investments
Icon-Slide menu
This is actually a demo page for a tutorial that can be found on the Codrops website. As Brian Yerkes pointed out on Twitter, it can be quite useful for a children’s website.

Icon Slide Menu

Kriesi.at
The Kriesi.at blog sports a very cool navigation that expands when hovered and displays an icon associated with that item. There is a jQuery plugin called Kwicks that can be used to achieve this effect. It’s a part of a Mootools plugin of the same name.

Kriesi.at

jQuery LavaLamp
This is one of my favorite effects, and Jolyon Terwilliger has done a truly great job writing the plugin. Check it out!

jQuery Lavalamp

Loewy Design
The Loewy Design website features a nice multilevel menu. It’s a simple effect but it looks nice, especially when the sub menu stays in the grid like in the image above.

Loewy Design

Bonadies Architect
The entire content of the Bonadies Architect website is animated with jQuery and it’s a pleasure to watch the boxes you see in the screenshot above unfold.

Bonadies Architect

Slice Machine
Slice Machine is a PSD slicing company and their website has a really nice garage door effect, both on the navigation and on the info segment as seen in the screenshot.

Slice Machine

Matthias Schütz
Matthias Schütz’s website has a cool slide-in main navigation. It is a simple effect but quite effective.

Matthias Schutz

Coda
Here we have another very influential site. Panic’s Coda is a very popular web development application for Mac OS and its website features a nice fade effect in the navigation. The popup on the Download link is also quite cool. The tabbed slider on the Coda website (you can see some of the tabs in the bottom of the screenshot) was the inspiration for the popular Coda-Slider jQuery plugin by Niall Doherty.

Coda

In Closing

I hope that you’ve enjoyed the tutorial and that it was easy to follow. Hopefully, you’ve learned some new techniques. If you have any questions or suggestions, don’t hesitate to post them in the comments below.

Useful Links

Marko is a freelance web designer & developer based in Serbia. He is always trying to improve his skills and create a better user experience for his clients. These days he is getting into writing and getting closer & closer to getting his degree in mechanical engineering.