jQuery animation glitch: functions fire in wrong order when mousing across to quickly
NOTE: I didn't write the script in question, my collegue did. Just volunteering to get some input on this for us. Please pardon incorrect terms or descriptions that sound like a noob; I'm not a scripting guy, I'm an HTML/CSS guy.
The page in question:
http://cure.org/curekids/kenya/2010/02/joseph_muchiri/
A screenshot of the issue:
The issue:
When you look at the page, you'll see a toolbar sort of dash at the top of the page, but just below the site header (its the piece that says "CUREkids").
When you hove开发者_Python百科r over any area of that toolbar there is a small green tab on the left that animates out from behind it (its the piece with the question mark on it). When clicked, the tab toggles open a descriptive Slidedeck interface. So far all is well.
The problem is that if you mouse across the toolbar too quickly, there is a screwy glitch that causes the jQuery rules to fire in a strange way that results in the tab coming out from behind, but going back in overtop of the toolbar.
Additional details:
The way the script works is that the tab is hidden behind the toolbar by default, and the jQuery first animates it left to come out away from the toolbar, then changes the z-index to bring it actually over top of the toolbar element for maximum usability and clicking area on the tab. All this happens on mouseOver. On mouseOut the reverse occurs (z-index changed to lower than the toolbar, and then animates right back to where it was located).
My thoughts
I think there must be an issue with how the script is written that possibly could be tweaked so that when the mouseOver event happens so quickly it doesn't result in the overlap bug.
All help is appreciated.
On the function you defined for mouseleave, add .stop(true, true)
before you change the z-index back to -1.
$("#what-tag").stop(true, true).css("z-index", "-1");
Check out http://api.jquery.com/stop/
The first true
passed to .stop(true, true)
will remove all queued animations. The second true
is the key in this situation - it basically jumps to the end of the function you defined for mouseenter and fires its callback immediately. In this case, by using .stop(true, true)
, you ensure that the z-index will always be set to 1 before setting it to -1.
I think what is currently happening is that it's setting the z-index to -1 before the mouseenter callback function fires.
Edit:
Unrelated - you should also look into caching your jquery selectors into variables. You are calling $("#what-tag")
six times in this hover method. If you define a variable above the hover method like this: var $whatTag = $("#what-tag")
and replace the references inside the hover method, it will work faster.
The best way I know of to fix this, and to control the behaviour with various options (like the interval in ms, timeout, sensitivity etc.) is the jQuery plugin, hoverIntent.
Just the default usage alone fixes the quick movement of the mouse triggering / queueing animations.
..instead of immediately calling the onMouseOver function, it waits until the user's mouse slows down enough before making the call.
Why? To delay or prevent the accidental firing of animations or ajax calls. Simple timeouts work for small areas, but if your target area is large it may execute regardless of intent.
If you want only to stop the queueing, then have a look at these articles / posts:
http://www.learningjquery.com/2009/01/quick-tip-prevent-animation-queue-buildup
http://css-tricks.com/full-jquery-animations/
What's happening is that the jquery animate function that is started on mouseover isn't finished when the mouseout event is fired... thus the 100ms delay before the z-index change is suppose to happen on the "show" part of the animation ends up happening after the z-index is changed on the mouseout "hide" function. (Hope that makes sense...)
So try this... change:
$("#curekids-dash").hover(function() {
$("#what-tag").show();
$("#what-tag").animate({left: "-13"}, 100, "linear", function() {$("#what-tag").css("z-index", "1");});
}, function() {
$("#what-tag").css("z-index", "-1");
$("#what-tag").animate({left: "10"}, 100, "linear", function() {$("#what-tag").hide();});
}
);
to:
$("#curekids-dash").hover(function() {
$("#what-tag").show();
$("#what-tag").animate({left: "-13"}, 100, "linear", function() {$("#what-tag").css("z-index", "1");});
}, function() {
$("#what-tag").clearQueue();
$("#what-tag").css("z-index", "-1");
$("#what-tag").animate({left: "10"}, 100, "linear", function() {$("#what-tag").hide();});
}
);
the important bit being the $("#what-tag").clearQueue();
In your mark-up, move the anchor-element #what-tag
outside of your div-element #curekids-dash
, for example, right in front of it:
:
:
<a class="toggle-trigger" id="what-tag" href="#">?</a>
<div id="curekids-dash">
<a id="curekids-home-link" href="/curekids">CUREkids<span class="hover-icon">(return to CUREkids home)</span></a>
<h1 id="helpChildNow"><a class="curekids-donate-link" href="https://secure.cure.org/curekids/donate?cause_id=5">Help <span id="childName">Joseph</span> Now</a></h1>
:
:
In curekids.css, line 24, for the selector #curekids-dash
, add the property z-index: 2;
, making the whole rule this:
#curekids-dash {
background:url("/img/curekids/ck-toggle-container.png") no-repeat scroll center center transparent;
height:80px;
position:relative;
width:960px;
z-index:2;
}
That fixed the issue in FF 3.6, and I'd be surprised if it doesn't fix it in IE, Webkit, and earlier FF-versions as well.
精彩评论