animating addClass/removeClass with jQuery

Johannes picture Johannes · Sep 5, 2011 · Viewed 346.2k times · Source

I am using jQuery and jQuery-ui and want to animate various attributes on various objects.

For the sake of explaining the issue here I've simplified it to one div that changes from blue to red when the user mouses over it.

I am able to get the behavior I want when using animate(), however when doing so the styles I am animating have to be in the animation code and so are separate from my style sheet. (see example 1)

An alternative is using addClass() and removeClass() but I have not been able to re-create the exact behavior that I can get with animate(). (see example 2)


Example 1

Let's take a look at the code I have with animate():

$('#someDiv')
  .mouseover(function(){
    $(this).stop().animate( {backgroundColor:'blue'}, {duration:500});
  })
  .mouseout(function(){
    $(this).stop().animate( {backgroundColor:'red'}, {duration:500});
  });

it displays all the behaviors I am looking for:

  1. Animates smoothly between red and blue.
  2. No animation 'overqueue-ing' when the user moves their mouse quickly in and out of the div.
  3. If the user moves their mouse out/in while the animation is still playing it eases correctly between the current 'halfway' state and the new 'goal' state.

But since the style changes are defined in animate() I have to change the style values there, and can't just have it point to my stylesheet. This 'fragmenting' of where styles are defined is something that really bothers me.


Example 2

Here is my current best attempt using addClass() and removeClass (note that for the animation to work you need jQuery-ui):

//assume classes 'red' and 'blue' are defined

$('#someDiv')
  .addClass('blue')
  .mouseover(function(){
    $(this).stop(true,false).removeAttr('style').addClass('red', {duration:500});
  })
  .mouseout(function(){
    $(this).stop(true,false).removeAttr('style').removeClass('red', {duration:500});
  });

This exhibits both property 1. and 2. of my original requirements, however 3 does not work.

I understand the reason for this:

When animating addClass() and removeClass() jQuery adds a temporary style to the element, and then increments the appropriate values until they reach the values of the provided class, and only then does it actually add/remove the class.

Because of this I have to remove the style attribute, otherwise if the animation is stopped halfway the style attribute would remain and would permanently overwrite any class values, since style attributes in a tag have higher importance than class styles.

However when the animation is halfway done it hasn't yet added the new class, and so with this solution the color jumps to the previous color when the user moves their mouse before the animation is completed.


What I want ideally is to be able to do something like this:

$('#someDiv')
  .mouseover(function(){
    $(this).stop().animate( getClassContent('blue'), {duration:500});
  })
  .mouseout(function(){
    $(this).stop().animate( getClassContent('red'), {duration:500});
  });

Where getClassContent would just return the contents of the provided class. The key point is that this way I don't have to keep my style definitions all over the place, but can keep them in classes in my stylesheet.

Answer

tw16 picture tw16 · Sep 6, 2011

Since you are not worried about IE, why not just use css transitions to provide the animation and jQuery to change the classes. Live example: http://jsfiddle.net/tw16/JfK6N/

#someDiv{
    -webkit-transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;
}