Watch
Watch jQuery Infinite Carousel screencast (Alternative flash version)
QuickTime version is approximately 15Mb, flash version is streaming.
View the demo used in the screencast
The Problem
I was recently asked to look at Dan Cederholm’s web site for a particular effect, but something I immediately noticed was the cool looking hover over/hover off effect on his images.
Wondering whether this was a CSS effect or done with jQuery, I did my usual repeat test: mouse over and out several times.
Unfortunately the effect goes a little wild. Admittedly this isn’t something the average user is going to do, but it is certainly possible that they’ll mouse over by accident, go out, then back in again to see what the text under behind the effect was. This would trigger a double effect, which I think still looks a little odd.
The fix is pretty easy once you know what to look out for.
Chainging to fadeTo
Dan’s original site code is:
$('.picture a').hover(function () {
$(this).find('strong').fadeIn('normal');
}, function () {
$(this).find('strong').fadeOut('normal');
});
There’s 3 things we need to do to stop this effect from happening:
- Add
stop()before the fade effect to prevent previous effects from finishing - Change the fade effects to use
fadeTo(speed, opacity)so they can animate from mid opacity - Change the CSS from
display:noneon thestrongelement toopacity: 0
$('.picture a').hover(function () {
$(this).find('strong').stop().fadeTo('normal', 1);
}, function () {
$(this).find('strong').stop().fadeTo('normal', 0);
});
Now the effect handles mousing over several times, and doesn’t continuously trigger.
Try the demo by moving your mouse over and out of the image.
Arguably, since the site’s CSS is using rgba(0, 0, 0, 0.746094) to handle the semi-opaque effect, you could get rid of the rgba in favour of a solid black background, and change the fadeTo('normal', 1) to fadeTo('normal', 0.746094). However, it should be noted, that use the opacity in the fade, rather than rgba results in the text being slightly transparent too, which may or may not be the desired effect.
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 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Repeat Animation Effect Fix</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
.picture {
border: 10px solid #ccc;
width: 600px;
margin: 40px auto;
position: relative;
overflow: hidden;
}
img {
width: 100%;
}
.picture strong {
background: rgba(0, 0, 0, 0.7);
top: 0;
display: block;
position: absolute;
text-align: center;
margin: 0;
padding: 20% 10px 10px 10px;
width: 100%;
height: 100%;
left: 0;
font-family: Georgia, serif;
color: #fff;
font-size: 35px;
opacity: 0;
-moz-opacity: 0;
filter:alpha(opacity=0);
}
.picture a {
text-decoration: none;
}
.picture strong span {
font-weight: bold;
font-family: 'Helvetica Neue', Helvetica, Arial;
}
.picture strong span.flick {
color: rgb(22, 120, 241);
}
.picture strong span.r {
color: rgb(255, 56, 159);
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.picture a').hover(function () {
$(this).find('strong').stop().fadeTo('normal', 1);
}, function () {
$(this).find('strong').stop().fadeTo('normal', 0);
});
});
</script>
</head>
<body>
<div class="picture">
<div>
<a href="http://www.flickr.com/photos/remysharp/4203307322/">
<strong>View on <span class="flick">flick</span><span class="r">r</span></strong>
<img src="http://farm3.static.flickr.com/2764/4203307322_33b32b9ff4.jpg" alt="video shoot" />
</a>
</div>
</div>
</body>
</html>

Play QuickTime version
Play Flash version
Tom On 23rd July 2009 at 14:07
Indeed a very common problem and thanks for your solution!
I actually have another problem which might be very common and maybe similar to fix? I googled a lot for this but the simpler the problems are, the harder to find are the solutions sometimes.
my (simplified) HTML:
my (simplified) jQuery:
Behaviour is as I expect, however I have 1 problem: hovering the <li> WHILE IT FADES OUT, fades the <li> right back in. How can I prevent that from happening?
Carlos On 23rd July 2009 at 17:07
Very instructive as always. Thank you for sharing.
Alex On 23rd July 2009 at 17:07
Ah I thought you were going to crack out an if statement, but this is far more effective; allows you to interrupt the fadeOut animation at any point and begin the fadeIn. Excellent.
By the way, what TextMate theme are you using?
Thomas Williams On 24th July 2009 at 04:07
Hi Remy - good pickup, I’ve had issues with high CPU usage on a hover effect and will try out your suggestions.
I mention this because when I mouse over/out quickly at the original site my CPU goes up to 60%. Your new version peaks at around 20% (I’m using Windows XP and Firefox 3.5).
Cheers, Thomas
Stugoo On 24th July 2009 at 11:07
Hi Remy,
Thanks again, I never knew that fadeTo exisited (doh). Once again your infinate wisdom helps to create a clean and wonderful JS function! :)
I would make a point on accessibility. Personally I wouldn’t use the opacity and display:block in the CSS as doesn’t invalidate it?
I would:
and in the jQuery function have
Then run the hover fade function?
How do you feel about that?
Nicolaj Kirkgaard Nielsen On 25th July 2009 at 10:07
Stugoo, I was thinking the same thing. I like the backward compatibility of your approach.
Remy, thanks for the tutorial. I’m fascinated by the autocomplete when you wrote the “opacity: 0;” instruction. How did you set that up and do you have any more autocomplete snippets you could share?
Michael Kozakewich On 25th July 2009 at 19:07
Just because of that, I’ve been eschewing fadeIn and fadeOut in favour .animate({opacity:”1″},{queue:false, duration:200})
fadeTo sounds better, though. Basically, I’m just doing .stop().fadeTo(200,1).
Nic On 25th July 2009 at 20:07
Great screencast, thanks!
mubs On 27th July 2009 at 23:07
The jQuery hoverFlow plugin (http://www.2meter3.de/code/hoverFlow/) was created for exactly this.
Stefan On 5th August 2009 at 09:08
Thank you very much for this, very helpful to me as I have just started learning jQuery. More please :-)
LuK On 5th August 2009 at 21:08
lol @mubs,
the first thing I thought was exactly your comment…I’ve had the same problem with a project and also found the .stop() method, but it wasn’t that beautiful as it looks, the problem is, that the animation gets stopped right at the point the other starts, even when it’s not finished, that leads to a “staggering” effect or even no effect at all, so I wanted something that ends the running animation (1 whole circle) and allows then another one…so I found the hoverFlow (Link see above) Plugin and was very pleased with it, it’s some kind of extended animation function and you just replace any .animate() with .hoverFlow(e.type, { css: “value”, css: “value” }, speed, easing); and you’re done…I like it a lot and it does just what it’s supposed to…I indeed hat a problem that I couldn’t solve with this one, and also stop didn’t what I expected from it =)…
I have the following function:
jQuery.fn.slideFadeToggle = function(settings) { settings = jQuery.extend({ speed:700, easing : "swing" }, settings) caller = this if($(caller).css("display") === "none"){ $(caller).animate({ height: 'toggle' }, settings.speed, settings.easing); $(caller).animate({ opacity: 1 }, settings.speed, settings.easing); }else{ $(caller).animate({ opacity: 0 }, settings.speed, settings.easing); $(caller).animate({ height: 'toggle' }, settings.speed, settings.easing); } };the whole thing is linked to an a-tag like this:
$("#slider-button").click(function(){ $("#formfield-container").slideFadeToggle() });the point is, I would like to have the same “make one complete animation cycle”-effect like on the hover things I do with .hoverFlow but in this case I couldn’t make it run, maybe because I don’t know where exactly to pass this function(e) from the hoverFlow Plugin…just in case somebody may know a solution to this =)….
thx in advance and thank you for the nice Screencasts!
Foamcow On 19th August 2009 at 11:08
So simple, yet easy to overlook.
I just fixed a little gallery rollover script that I made and it’s now about 95% less annoying!
Thanks Remy!
Ben On 2nd September 2009 at 09:09
Hi, just wanted to report a typo: You wrote “…use fadeIn(speed, opacity) so…” but judging from your subsequent code and the jQuery docs I think you meant “fadeTo” in that sentence. Anyway, thanks for the straightforward example of how to fix this problem!
Peter Collins On 26th October 2009 at 18:10
Wonderfully easy to understand tutorial. The first one I’ve used for jQuery where I understood it and was able to implement it to the code I had to stop a small but annoying quirk.
Thank you, I very much appreciate the work you’ve put into the video.