This episode is revisiting the image cross fade effect, in particular Dragon Interactive has a beautiful little transition for their navigation that some readers have been requesting. Greg Johnson takes it one step further to implement this method using jQuery and the methods shown here.
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);
});
});
});
July 28, 2008 at 13:31
Just lovely - thanks for this. I so appreciate techniques that degrade this flawlessly.
July 28, 2008 at 14:18
Thanks so much for this. I was following your discussion with Greg, and I'm so glad to see this clean description hit your site. Very helpful for js & jquery newbies like myself. Your blog is a staple in my RSS reader.
Thanks again!
July 28, 2008 at 14:35
I loved watching the tutorial screencast. It was great to see your train of thought as you worked on the problem, and even more encouraging to see a great jquery developer making the same mistakes I make (and following the same processes to find and fix them).
As you said in the video, I'm sure you prefer to put out flawless videos, but I'd like to encourage this type of video that really helps the audience identify with the presenter!
July 28, 2008 at 14:50
Very neat. Might be worth extending very slightly by handling focus/blur events so keyboard users will get the same effects when tabbing through.
Not tried it locally, but I think you can just add .focus and .blur events, and if you make the hover function handlers into separate functions you can just call them from focus and blur events too.
July 28, 2008 at 15:10
Excellent effect and whoever was first in coming up with the technique: kudos!
But wasn't this effect available on http://ui.jquery.com/ for a while now as well? Or was Dragon first?
July 28, 2008 at 16:38
ui.jquery thank Dragon Interactive in their source code for coming up with the effect.
Having this method was very important to me, so I'm very grateful for the help.
I used it to develop a free WordPress theme. It's not officially released yet, but have a sneak peak at the wp coda theme.
July 28, 2008 at 16:54
Wow wicked cool! Thankssssssssssssssss a zillion.
July 29, 2008 at 08:09
It seems flash :) Thank you for sharing these great tutorials Greetings from Italy
July 30, 2008 at 08:51
This was amazing, I was looking for something like this for a long time now!...
I just have one more question about it, which by the way I have already tried finding out a solution but couldn't, and it is the "CURRENT" state of the button. The page that we are currently on has a different color of fade. I believe this new position of the buttons large image comes from the CSS, but how do I test the current page and execute that particular piece of code?....
Thank for the help in advance!
Jeremy
August 4, 2008 at 12:10
thnx for ur awesome tutorials :)
August 5, 2008 at 21:52
Thank you for the screencast.
August 6, 2008 at 14:52
Thanks for your nice screencasts. They are really very nice and useful Thanks a lot...
August 6, 2008 at 15:52
Hi, I'm using fading script in big logo-image. How can I fadeTo (and off) random background areas while page is loaded? - Without interruption; one after another and only one element in the same time. Greetings.
August 10, 2008 at 20:41
Another wonderful screencast, a lot of things more learned. Every time a discovery. Thanks.
August 12, 2008 at 08:34
I have something like this that works (well) in IE6: http://okb.no Not quite made for release, but works perfectly in all major browsers as set up on our site.
August 21, 2008 at 12:24
heya buddy. Awesome tutorial, and a stunning effect.
i was just wondering if you could help me make it a little more awesome.... I want to achieve the same effect, but retain the text. So that I don't have to render an image (or 2) with the text in the image, I want to create 1 button, and then use the html of the anchor to do the text.
This would mean that that button is then re-usable for most buttons in a design, without having to re-render a new image every time you want the button to say something different!
Any help appreciated, I think I'm nearly there, but this would make the technique invaluable!
Cheers
Jay
September 25, 2008 at 13:58
Hi I have an issue! please bare with me since I am very new to this whole web dev thing. I was wondering how I can make <li> stay to the left of the page? since I include this navigation into my my template with php include..it messes up the entire template display because the navigation starts off a bit away from the left side of the page!
Any help would be appreciated.
Thank you! Ryan .J
September 28, 2008 at 17:54
How can i highlight the selected link for a particular page using this style of menu?
October 10, 2008 at 07:44
I had the same question... Anybody please? Thank you
October 20, 2008 at 15:56
I adapted your code for a test page located at architerra.com/damask2.lasso (to be inserted into a frame once live.) It works fine in Firefox, but nothing renders at all in Safari. I have compared our code - yours works in both - and cannot nail down what is going wrong.
Can anyone else see the problem?
November 2, 2008 at 14:20
Hi,
FINALLY! i found this great link...
Actually i would need some help actually..i need to have prototype and scriptaculous in my website but i would love to use your script.
Is it possible that you tell me how you can use jQuery.noConflict(); here in this case?
I know i have to substitute "$" to jQuery but everytime i put the code " jQuery.noConflict(); " it disables the whole website. I dont know what's wrong!
Would be glad if u can help. thanks!