Correctly Fading in/out onmouseover Using jQuery

I've had a bit more trouble than I should have getting HTML objects to intuitively fade in or out when you mouse over them.  When I finally decide to invest some actual time on such a small project, I got some clean and solid code as a result, so I thought I would share it here.

Here's what I'm talking about:

Mouse over me!



I've run into the idea on a few different projects where I wanted something to toggle fade in/out when the user clicked or hovered on an object.  This can be useful if you want to fade in a close button only when the user's mouse is over the element, or an upload button when the user mouses over their profile icon, etc.



At first simply using jQuery's fadeIn and fadeOut (or fadeToggle) methods seemed to work quickly and easily.  However, when the user can rapidly toggle between the two, I started to notice some buggy feeling behavior.


Consider the code below and it's working example:

  $('.hiddenFormMouseover').mouseenter(function() {
      $(this).children('.hiddenFormMouseoverButton').fadeIn();
  });
  $('.hiddenFormMouseover').mouseleave(function() {
      $(this).children('.hiddenFormMouseoverButton').fadeOut();
  });


Mouse over me!


The effect seems to be fine at first glance, but try running the mouse rapidly over and out of the object repeatedly.  You'll notice that after you stop moving your mouse, the object continues to fade in and out for as many times as you moused over it.  This is because the functions are just tossed onto the stack every time they are called by your mouse movement, and each must wait for the previous ones to finish before it can execute.  If your mouse moves quicker than the object can fade, then it will continue to oscillate after you finished.


This is actually the intended result for jQuery, but it's probably not what you want in your interface.  If your mouse is over the object,  it should immediately fade in and stop.  Vice versa if your mouse moves outside the object.


I next tried a few different combinations of adding things into my functions like jQuery's stop() (stops the fade in or out currently in progress) and passing 0 as the time argument to my fade functions (like fadeOut(0) which causes the object to immediately fade out).  I continued to get slightly better but still not perfect behavior, like objects stopping while half opaque instead of continuing to oscillate, until I thought out exactly what I wanted to happen and got it right.


When the cursor enters the object, we want the object to stop any other fading it might be doing and run the full fadeIn animation.  When the cursor leaves we want the opposite; stop fading, and then run a full fadeOut.


Writing that out in javascript we get an intuitively behaving solution:


  $('.hiddenFormMouseover').mouseenter(function() {
    $(this).children('.hiddenFormMouseoverButton').stop();
    $(this).children('.hiddenFormMouseoverButton').fadeOut(0);
    $(this).children('.hiddenFormMouseoverButton').fadeIn();
  });

  $('.hiddenFormMouseover').mouseleave(function() {
    $(this).children('.hiddenFormMouseoverButton').stop();
    $(this).children('.hiddenFormMouseoverButton').fadeIn(0);
    $(this).children('.hiddenFormMouseoverButton').fadeOut();
  });



Mouse over me!




That's the same example as the one at the top of this post, for the record.  Try all the crazy mousing you want and the fading should behave exactly as you'd expect.


There you have it, a simple concept but one that might otherwise take awhile to get implemented correctly.