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);
});
});
});
You should follow me on Twitter here I tweet about jQuery amongst usual the tweet-splurges!
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
loy On 19th July 2009 at 04:07
can anyone help me? i’m using pngs for my images so they have transparent background. but when i use the effect/script, the original image still shows since the hover image doesn’t cover it up entirely.
here’s my test site to see what’s going on: http://www.kaloyster.com/jquerytest.html
hope you can help with my problem. thanks in advance!
Dominik On 14th August 2009 at 08:08
Hi! Your Script is really great, but I’ve a problem. I’m working on a Submenu. And when this submenu comes out from one , and I go down with the cursor, the top Menu <a> is no longer in hover color. What do I have to change, that the <a> is in hover color?
It looks like this: …
Samuel On 15th August 2009 at 06:08
Hi! Loved the tutorial, it’s very functional and versatile but I need help in something… I was trying to put the script into my Wordpress theme for the main highlights and articles in the index page instead of just as a navigation bar.
I was going to configure the files for setting only the images and the posts in the theme properties and writing manually every class in the CSS file but I realized that I could improve it a little bit and instead of just writing and recycling classes in the CSS every time that there is an update, I could use in-line styles over the <a> element for the background-image src and leave the background-positions to be handled by the CSS file as usual. The thing is, I need that each <span> after the <a> copy the “style” attribute from the <a> as if the function was running like this:
Can anyone help me?
james8701 On 19th August 2009 at 04:08
i’m having a problem in ie with the transparency in the menu, it seems to have a black image when i hover, i really appreciate if anyone could give me hand on this, tnx!
CodeWarrior On 23rd August 2009 at 17:08
Hey Guys, I have a question. I use this code and I love it but I got a problem. I want to use text because of SEO and a background, and only the background picture shoud fade. It works good except that the text fades too so that it fades away but when opacity is 1 it appears again. Thanks for help CodeWarrior
Jeremy On 4th September 2009 at 14:09
Just getting into web coding, and this was great! Great tutorial, well done. Makes me even more interested to know that someone can just change their mind and switch things around with such ease. Gives me a far better perspective.
Lane On 7th September 2009 at 01:09
Hi Rem! As usual, great tut. One question, how would you keep a link faded in when it is active? (ie. Keep Portfolio lit up when you are on the portfolio page?)
Lane On 7th September 2009 at 02:09
Nevermind. I figured it out. Just added this to the js:
$(’#nav li a’).filter(function () { return !$(this).hasClass(”active”); }) .append(”).each(function() {
and this to the CSS
ul .hi a#home:hover, ul a#home span.hover ul a#home.active {
width: 49px; background-position: -158px -30px;
}
Al On 23rd September 2009 at 20:09
hi, i ‘ve just used that navigation thing, but it seems doesn’t work well ’cause i put other image instead dragon-sprite.jpg and i added the transitions on the image just like the original, but it doesn’t do anything, if anyone could help me i’d apreciate it tnx :)
vale On 27th September 2009 at 14:09
Hey thanks for explaining this, great tutorial. I’m not understanding how to let this fallback fine when javascript is disabled (or the user is using IE6) keeping the background shift on link’s hover state. Thanks.
Vale On 30th September 2009 at 20:09
If you disable javascript on the demo page, is not going to fallback to the css original version of the navbar (background position swapping on mouse hover).
Ben On 17th October 2009 at 07:10
Thanks for the code, still useful today! I’ve employed this code for a site I’m working on for my friend who is using a vertical scroller with images as a navigation for his portfolio. What I am trying to do now is activate the hover image of the specific image when it is clicked on, so it appears in full opacity compared to the others. I didn’t quite understand what Lane did. I’ve created a new class with the same properties as the hover and added it through some pathname/indexOf logic to the link, but with no success. Any help would be appreciated. http://www.randyberinger.com/kiwi. Thanks!
scherii On 21st October 2009 at 08:10
First I’d like to thank you for this great website.
Do you know how to fade transparent pngs in IE (without that annoying black border)? I’ve tried it with unitpngfix - but that does not seem to work..
Quinn On 27th December 2009 at 21:12
Hello - i’m having problems with this on Internet Explorer. The leftmost “button” on both instances of the nav running on my site seem to float on top of the other ones… only in IE! If anyone can look at the code and help I would be grateful! — http://quinnianniciello.com Thanks!
Dimbeko On 5th January 2010 at 00:01
Another great script!
I have been using it for my website main menu: http://www.dabproject.com/ No issues, no errors, extremely easy to implement and modify. It shows a real power of JQuery!
The script can be used anywhere, not only for menu elements. I have an idea to use it like roll-over for my portfolio demonstration but have not implemented yet.
Thank you!
Mike On 24th January 2010 at 03:01
Hey guys,
Below is my version of the code. I have tested this and the fading effect displays EXACTLY the same in IE6, IE8, FF3.5 (win + linux), Chrome 3 (win + linux), Konqueror (linux) and Opera (linux). It degrades nicely when javascript is turned off (simple css rollover) and contains the link text when the style sheet is disabled. Can anyone spot anything wrong with this version? (as I am new to css, javascript and jquery - it seems to work a little too well).
[Author edit: moved to JS Bin]: http://jsbin.com/iroxu3/edit#html