Watch the image fade revisited screencast (alternative flash version)
QuickTime version is approximately 30Mb, flash version is streaming.
View the demo and source code used in the screencast
Also a side note about IE6 support:
Side note: IE6 screencast (alternative flash version)
Understanding the Problem
So let’s break this down and see how it’s done.
The first thing I look for when understanding how a web effect has been achieved, is to look at what they’ve done when JavaScript is disabled. Where possible, I always want to produce a solution that works cleanly without JavaScript enabled.
Since Dragon Interactive are using the effect for navigation, as I suspected, the effect degrades to…nothing. Although we’ll take it one step further by creating a hover state for the navigation.
The second thing I’ll look at is the difference between the sent markup and the rendered markup. This gives me the clues I need to understand what’s going on behind the scenes without having to read their JavaScript.
The key in their version is there is a new span within the hover area that isn’t in the sent markup. So this is what’s being created using JavaScript, and this is also the key to the whole effect.
From this, we can see when the anchor is hovered over, the newly created span’s opacity is faded up and completes the transition effect.
HTML
Note that our default HTML has this extra class="highlight" because I want the hover effect to still trigger if JavaScript is disabled. We’ll strip out this class in the jQuery later on. It also means we’ll have slightly more CSS to support both the hover state and the jQuery based hover state.
Also, everything with the anchor will be hidden due to the #navigation a * { display: none; } rule. This means with CSS turned off the navigation still works.
<ul id="navigation">
<li class="highlight"><a href="#" class="home"><span>Home</span></a></li>
<li class="highlight"><a href="#" class="services"><span>Services</span></a></li>
<li class="highlight"><a href="#" class="portfolio"><span>Portfolio</span></a></li>
<li class="highlight"><a href="#" class="about"><span>About</span></a></li>
<li class="highlight"><a href="#" class="contact"><span>Contact</span></a></li>
</ul>
CSS
This is only a snippet of the CSS (for full CSS see the working example). We’re using a CSS sprite and changing the background position both in the a:hover state and for the jQuery create span.
#navigation a * {
display: none;
}
#navigation a,
#navigation a .hover {
height: 70px;
position: relative;
display: block;
background: url(images/dragon-sprite.jpg) 0 0 no-repeat;
}
#navigation a.home {
background-position: 0 0;
width: 102px;
}
/* .highlight will be remove if JS is enabled */
#navigation .highlight a.home:hover,
#navigation a.home .hover {
background-position: 0 -280px;
width: 102px;
}
jQuery
Finally, all that’s left is to create the new span and fade it up and down when we hover over.
$(function () {
// IE6 doesn't handle the fade effect very well - so we'll stick with
// the default non JavaScript version if that is the user's browser.
if ($.browser.msie && $.browser.version < 7) return;
$('#navigation li')
// remove the 'highlight' class from the li therefore stripping
// the :hover rule
.removeClass('highlight')
// within the context of the li element, find the a elements
.find('a')
// create our new span.hover and loop through anchor:
.append('<span class="hover" />').each(function () {
// cache a copy of the span, at the same time changing the opacity
// to zero in preparation of the page being loaded
var $span = $('> span.hover', this).css('opacity', 0);
// when the user hovers in and out of the anchor
$(this).hover(function () {
// on hover
// stop any animations currently running, and fade to opacity: 1
$span.stop().fadeTo(500, 1);
}, function () {
// off hover
// again, stop any animations currently running, and fade out
$span.stop().fadeTo(500, 0);
});
});
});
Related posts
Demo
If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.
Source Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Image Fade Revisited</title>
<style type="text/css" media="screen">
body {
font-family: helvetica;
}
#navigation {
list-style: none;
}
#navigation li {
float: left;
}
#navigation a * {
display: none;
}
#navigation a,
#navigation a .hover {
height: 70px;
position: relative;
display: block;
background: url(images/dragon-sprite.jpg) 0 0 no-repeat;
}
/* individual navigation items */
#navigation a.home {
background-position: 0 0;
width: 102px;
}
#navigation .highlight a.home:hover,
#navigation a.home .hover {
background-position: 0 -280px;
width: 102px;
}
#navigation a.services {
background-position: -102px -140px;
width: 115px;
}
#navigation .highlight a.services:hover,
#navigation a.services .hover {
background-position: -102px -280px;
}
#navigation a.portfolio {
background-position: -217px 0;
width: 120px;
}
#navigation .highlight a.portfolio:hover,
#navigation a.portfolio .hover {
background-position: -218px -280px;
}
#navigation a.about {
background-position: -337px 0;
width: 100px;
}
#navigation .highlight a.about:hover,
#navigation a.about .hover {
background-position: -339px -280px;
}
#navigation a.contact {
background-position: -437px 0;
width: 115px;
}
#navigation .highlight a.contact:hover,
#navigation a.contact .hover {
background-position: -440px -280px;
}
</style>
<!--[if IE]>
<style type="text/css" media="screen">
#navigation a .hover {
cursor: pointer;
}
</style>
<![endif]-->
<script src="jquery-1.2.6.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
$(function () {
if ($.browser.msie && $.browser.version < 7) return;
$('#navigation li')
.removeClass('highlight')
.find('a')
.append('<span class="hover" />').each(function () {
var $span = $('> span.hover', this).css('opacity', 0);
$(this).hover(function () {
// on hover
$span.stop().fadeTo(500, 1);
}, function () {
// off hover
$span.stop().fadeTo(500, 0);
});
});
});
</script>
</head>
<body>
<h1>Image Fade - Revisited</h1>
<div id="intro">
<p>This technique revisits image fade transitions, following the techniques shown on the Dragon Interative web site. <br /><a href="http://jqueryfordesigners.com/image-fade-revisited">Read the article, and see the screencast this demonstration relates to</a></p>
</div>
<ul id="navigation">
<li class="highlight"><a href="#" class="home"><span>Home</span></a></li>
<li class="highlight"><a href="#" class="services"><span>Services</span></a></li>
<li class="highlight"><a href="#" class="portfolio"><span>Portfolio</span></a></li>
<li class="highlight"><a href="#" class="about"><span>About</span></a></li>
<li class="highlight"><a href="#" class="contact"><span>Contact</span></a></li>
</ul>
</body>
</html>

Play QuickTime version
Play Flash version
Niels On 25th February 2009 at 10:02
That’s awsome Richard, now how do I tie this to an onClick event? because I’d like the fade to stick when it’s clicked on, without refreshing the page… =)
Reece Conrad On 5th May 2009 at 00:05
I was just now checking out this older article. I noticed that it didn’t work in IE6 on this site, but when I downloaded and tried it on my server, it worked fine. (I removed the “if ($.browser.msie && $.browser.version < 7) return;”) and it worked fine.
Why did you add that line? Do I have a magical version of IE6? :P
Tom On 5th May 2009 at 01:05
I have found a fix to make it works with .PNG “hover” images… meaning, instead of having 2 images, or sprites about the hover state and normal… Just to have normal states, and in the over method, fadein-out the PNG My code:
[code] .append(”).each(function () { $(’div.hover’, this).css(”background-image”, “url(”+ $(”img”, this).attr(”src”) +”)”); var $span = $(’div.hover’, this); $(this).hover(function () { // on hover $span.stop().fadeTo(500, 0); }, function () { // off hover $span.stop().fadeTo(500, 1); }); }); [/code] You can note the difference is not sooo big. Anyway I am so happy to fix it (some movements before, I was having trouble with black png instead of really transparent)
Michael Turner On 31st May 2009 at 21:05
Great work - I’ve been playing with this effect for six months (using two images) to grand effect! Now, I would like to use a third image to render not as a link, but as a static image indicating which page is selected.
You can see what I’m working on at http://www.architerra.com/annav.html
The .png is located at http://www.architerra.com/img/annav.png
Basically, I suppose I need a new class to use in place of “navigation” that I can adapt from page to page to show the image seen on the third row. Any help would be appreciated!
Yours, Michael
Linus Ekenstam On 4th June 2009 at 08:06
Hi!
Great tutorial, but how do i get the yellow part of the sprite to show? like when we are at the selected pagei wanna show? Like if I’m at the start page i want i to be yellow, this must be a lame question but i just cant figure it out…
Please some help?
Mail me: Linus@winternet.se
Facio Design On 1st July 2009 at 07:07
Great, easy to understand tutorial. Thanks for putting these jquery tutorials together