Bram Vanroy
Bram Vanroy

Reputation: 28427

Animation problems with jQuery

Fiddle.

Relevant code (also annotated in fiddle):

// tooltip positioning on hover and overlay fade on all li's except for submenu items that are not the last child
$("ul:not(.sub-menu) > li, ul.sub-menu > li:last-child").not(":has(ul.sub-menu)").hover(function () {
  var $this = $(this),
    title = $(this).children("a").data("title"),
    posL = $this.offset().left + ($this.width() / 2),
    posT = $this.height(),
    tooltip = $("#tooltip"),
    overlay = $("#overlay");

  $this.addClass("over-down");
  overlay.stop(true).fadeIn("slow"); // RELEVANT FOR QUESTION
  tooltip.stop(true, true).text(title).animate({ // RELEVANT FOR QUESTION
    "left": posL - (tooltip.width() / 2),
      "top": posT + $this.offset().top + 20
  }, 300).fadeIn("fast");
}, function () {
  var $this = $(this),
    tooltip = $("#tooltip"),
    overlay = $("#overlay");

  $this.removeClass("over-down");
  overlay.stop(true).fadeOut("slow"); // RELEVANT FOR QUESTION
  tooltip.stop(true).fadeOut(400); // RELEVANT FOR QUESTION
});

In the fiddle, try hovering over an item, then briefly leaving it and hovering another item. You will see that the #overlay div has partially faded out, as has the #tooltip span. What I want is a smooth transition between the two, so normally, tooltip and overlay should fadeIn again to a 100%, but they don't. I have been messing around with that .stop() but nothing seems to work.

This problem occurs on every browser tested (IE10, FF, Chrome).

Upvotes: 1

Views: 132

Answers (1)

Fabrício Matté
Fabrício Matté

Reputation: 70139

When you .stop(true) in the middle of a fadeOut, the item will not be set to display:none hence the next fadeIn will have no effect.

There are 2 possible solutions:

Using .stop(true, true) before the fadeIn will force an abrupt display:none on the element and hence enable a fadeIn in succession. This is not a very smoothly solution. Fiddle

Another solution is to use fadeTo instead of fadeIn. fadeTo will animate the opacity similar to fadeIn, but without the display:none requirement. It also works on hidden elements fading them in as fadeIn does:

$this.addClass("over-down");
overlay.stop(true).fadeTo(600, .75); //edited here
tooltip.stop(true, true).text(title).animate({ //here*
    "left": posL - (tooltip.width() / 2),
    "top": posT + $this.offset().top + 20
}, 300).fadeTo(200, 1); //and here

Fiddle

This is a way more smoothly solution. It will animate the element properly back to .75 opacity independently of its current opacity or display.

*Added a .stop(true, true) to the tooltip so it doesn't stay half-faded while your fadeTo is queued. If you want to slide such them, try:

var do_dequeue = tooltip.is(':visible');
tooltip.stop(true).text(title).animate({ // RELEVANT FOR QUESTION
    "left": posL - (tooltip.width() / 2),
    "top": posT + $this.offset().top + 20,
}, 300).fadeTo(200, 1);
if (do_dequeue) tooltip.dequeue();

Fiddle

The do_dequeue var keeps track of whether the tooltip was partially faded before preparing the move then fade queue, if it is partially faded then it won't wait for the tooltip to be placed under the element before fading it back to full opacity. I guess this is the smoother it can get. =]

Upvotes: 1

Related Questions