views:

103

answers:

4

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:

http://cl.ly/2kUe

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 hover 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.

A: 

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();

Chris
Nope. Thanks anyway. The z-index bit still occurs, but it just doesn't animate out quite as far apparently. Did you test that in firebug or just write from knowledge? If you tested it, did it successfully remove the blip in your browser?
JAG2007
Hmm... yea, I typed it from knowledge of having the same problem myself a while back... but I could be combining things. Maybe also try $("#what-tag").stop();
Chris
Just read this response, yeah `.stop()` is the answer, but it needs to be `.stop(true, true)`.
Bryan Downing
A: 

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"&gt;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.

Thomas
The only reason this worked is because the top left corner of #curekids-dash just happens to be at the same location as the top left corner of #mainContent AND #mainContent has position relative. If either of those conditions were false, it would break.
Bryan Downing
+1  A: 

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/

Moin Zaman
I would have awarded you the answer, but strictly speaking Bryan's solution of adding .stop(true, true) to the function worked perfectly without even having to add a plugin. But we did opt to add hoverIntent to our common.js and are using it there as well as a crapload of other places on our site. It really does make for a more polished user experience with the interface IMO. Thanks for the suggestion!!
JAG2007
no worries, glad to be of help. I agree, hoverIntent goes with me where I go for a nice hover experience
Moin Zaman
+1  A: 

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.

Bryan Downing
Excellent - worked like a charm. Also decided on using hoverIntent for added polishing.
JAG2007