239
votes

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.

6
What versions of IE do you need to support? Would you be happy with IE9? Or do you need to support lower?tw16
I'm not caring about IE at all to be honest. This has all been tested with webkit browsers only (safari/chrome).Johannes
how getClassContent is looks like?sreginogemoh

6 Answers

328
votes

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;
}
99
votes

Another solution (but it requires jQueryUI as pointed out by Richard Neil Ilagan in comments) :-

addClass, removeClass and toggleClass also accepts a second argument; the time duration to go from one state to the other.

$(this).addClass('abc',1000);

See jsfiddle:- http://jsfiddle.net/6hvZT/1/

38
votes

You could use jquery ui's switchClass, Heres an example:

$( "selector" ).switchClass( "oldClass", "newClass", 1000, "easeInOutQuad" );

Or see this jsfiddle.

13
votes

You just need the jQuery UI effects-core (13KB), to enable the duration of the adding (just like Omar Tariq it pointed out)

5
votes

I was looking into this but wanted to have a different transition rate for in and out.

This is what I ended up doing:

//css
.addedClass {
    background: #5eb4fc;
}

// js
function setParentTransition(id, prop, delay, style, callback) {
    $(id).css({'-webkit-transition' : prop + ' ' + delay + ' ' + style});
    $(id).css({'-moz-transition' : prop + ' ' + delay + ' ' + style});
    $(id).css({'-o-transition' : prop + ' ' + delay + ' ' + style});
    $(id).css({'transition' : prop + ' ' + delay + ' ' + style});
    callback();
}
setParentTransition(id, 'background', '0s', 'ease', function() {
    $('#elementID').addClass('addedClass');
});

setTimeout(function() {
    setParentTransition(id, 'background', '2s', 'ease', function() {
        $('#elementID').removeClass('addedClass');
    });
});

This instantly turns the background color to #5eb4fc and then slowly fades back to normal over 2 seconds.

Here's a fiddle

2
votes

Although, the question is fairly old, I'm adding info not present in other answers.

The OP is using stop() to stop the current animation as soon as the event completes. However, using the right mix of parameters with the function should help. eg. stop(true,true) or stop(true,false) as this affects the queued animations well.

The following link illustrates a demo that shows the different parameters available with stop() and how they differ from finish().

http://api.jquery.com/finish/

Although the OP had no issues using JqueryUI, this is for other users who may come across similar scenarios but cannot use JqueryUI/need to support IE7 and 8 too.