jQuery Animation

March 29th, 2010
By: Cory Mathews

I was recently working with the .animate() function and found there are some really cool effects you can create with it. However the more I used it the more problems I ran into.

Basic usage of .animate()

Just for good measure here is the basic usage of the .animate() function. I won’t go to far into this, check out the jQuery API for more.

$("#SomeID").animate({ width: '50px' }, { duration: 500 });

This animates the id SomeID to a width of 50px over 500 milliseconds with a basic linear slide transition.

The “animation” queue. (or so I will call it)

When jquery runs the .animate() function it runs it along side other javascript. This allows me to add multiple animations to a queue and then run one after another instead of all at the same time. For example

$("#SomeID").animate({ width: '50px' }, { duration: 500 });
$("#SomeID").animate({ width: '150px' }, { duration: 500 });
$("#SomeID").animate({ width: '50px' }, { duration: 500 });
$("#SomeID").animate({ width: '150px' }, { duration: 500 });

This code will animate an id from a width of 50px to 150px to 50px to 150px one after another so I see a nice smooth slide from one stage to the next.

Now this code.

$("#SomeID").animate({ width: '50px' }, { duration: 500 });
$("#SomeID").animate({ width: '150px' }, { duration: 500 });
$("#SomeID").animate({ width: '50px' }, { duration: 500 });
$("#SomeID").animate({ width: '150px' }, { duration: 500 });
alert('hi');

Notice the alert appears to run first. This got me until I stopped to really think about the animation queue.

Take a look at this example from learning jquery

$(document).ready(function() {
  $('ul.anim_queue_example1 a').hover(function() {
    $(this).animate({ left: 20 }, 'fast');
  }, function() {
    $(this).animate({ left: 0 }, 'fast');
  });
});

This is a simple hover effect for a list menu. The problem may not be easily spotted at first but try it out. Running your mouse over the menu quickly will cause the queue to fill up with animations and continue running them long after you stop. More then likely not the desired effect.

Brandon Aaron was easily able to fix this by adding a simple .stop() to the functions.

This now gives you this code

$(document).ready(function() {
  $('ul.anim_queue_example2 a').hover(function() {
    $(this).stop().animate({ left: 20 }, 'fast');
  }, function() {
    $(this).stop().animate({ left: 0 }, 'fast');
  });
});

Adding the .stop() function will stop the current animation in the queue before running the next animation and will fix the problem.

Ok, now for the example problem that does not get fixed by calling .stop().

For the next example I am going to be using thepause plugin by Johnathan Howard and posted below

$.fn.pause = function(milli) {
  milli = milli || 1000;
  return this.queue("fx",function(){
    var self = this;
    setTimeout(function(){$.dequeue(self);},milli);
  });
};

Now check out the following:

$("#SomeID, #SomeID2").animate({ width: '50px' }, { duration: 500 }).pause(350);
$("#SomeID, #SomeID2").animate({ width: '150px' }, { duration: 500 });
$("#SomeID, #SomeID2").animate({ width: '50px' }, { duration: 500 }).pause(350);
$("#SomeID, #SomeID2").animate({ width: '150px' }, { duration: 500 });
$("#someID3").hover(function() {
$("#SomeID , #SomeID2").stop().height(50).width(50).animate({ width: '150px' }, 500);
} , function() {
$("#SomeID ").stop().animate({ width: '50px' }, 200);
$("#SomeID2").stop().animate({ width: '50px' }, 200);
});

This example will stop the current animation but when that short pause ends it will continue with the queue and mess with the desired animated effects. To stop this problem is actually pretty easy. To solve it change .stop() to .stop(true, false). This is because in .stop(true, false) the first true is the clearQueue parameter. This will clear all queued actions for the object. Meaning that all the future animations, once delayed, are now removed and will not interfere with the hover event.

More problems

1 more problem I have not looked into solving put probably will have to eventually is the problem of keeping those animations until after the hover is finished. Not every time will I want to completely clear the queue. I could see it being likely that I would want to do something more like the following:

$("#someID3").hover(function() {
$("#SomeID , #SomeID2").pauseQueue().animate({ width: '150px' }, 500);
} , function() {
$("#SomeID , #SomeID2").stop().animate({ width: '50px' }, 200).startQueue();
});