
Creating custom animations
In addition to the prebuilt effect methods, jQuery provides a powerful .animate()
method that allows us to create our own custom animations with fine-grained control. The .animate()
method comes in two forms. The first takes up to four arguments:
- An object of style properties and values, which is similar to the
.css()
argument discussed earlier in this chapter - An optional duration, which can be one of the preset strings or a number of milliseconds
- An optional easing type, which is an option that we will not use now, but which we will discuss in it in Chapter 11, Advanced Effects
- An optional callback function, which will be discussed later in this chapter
All together, the four arguments look like this:
.animate({property1: 'value1', property2: 'value2'}, duration, easing, function() { alert('The animation is finished.'); } );
The second form takes two arguments: an object of properties and an object of options:
.animate({properties}, {options})
In effect, the second argument wraps up the second through fourth arguments of the first form into another object and adds some more advanced options to the mix. When we adjust the line breaks for readability, the second form looks like this:
.animate({ property1: 'value1', property2: 'value2' }, { duration: 'value', easing: 'value', specialEasing: { property1: 'easing1', property2: 'easing2' }, complete: function() { alert('The animation is finished.'); }, queue: true, step: callback });
For now, we'll use the first form of the .animate()
method, but we'll return to the second form later in the chapter when we discuss queuing effects.
Building effects by hand
We have already seen several prepackaged effects for showing and hiding elements. To begin our discussion of the .animate()
method, it will be useful to see how we could achieve the same results by calling .slideToggle()
using this lower-level interface. Replacing the .slideToggle()
line of the previous example with our custom animation turns out to be quite simple:
$(document).ready(function() { var $firstPara = $('p').eq(1); $firstPara.hide(); $('a.more').click(function(event) { event.preventDefault(); $firstPara.animate({height: 'toggle'}, 'slow'); var $link = $(this); if ($link.text() == 'read more') { $link.text('read less'); } else { $link.text('read more'); } }); });
Listing 4.13
Tip
This is not a perfect replacement for .slideToggle()
; the actual implementation also animates the margin and padding of elements.
As the example illustrates, the .animate()
method provides convenient shorthand values for CSS properties, such as 'show'
, 'hide'
, and 'toggle'
, to ease the process when we want to emulate the behavior of prepackaged effect methods such as .slideToggle()
.
Animating multiple properties at once
With the .animate()
method, we can modify any combination of properties simultaneously. For example, to create a simultaneous sliding and fading effect when toggling the second paragraph, we simply add the opacity property-value pair to the properties object of .animate()
:
$(document).ready(function() { var $firstPara = $('p').eq(1); $firstPara.hide(); $('a.more').click(function(event) { event.preventDefault(); $firstPara.animate({ opacity: 'toggle', height: 'toggle' }, 'slow'); var $link = $(this); if ($link.text() == 'read more') { $link.text('read less'); } else { $link.text('read more'); } }); });
Listing 4.14
Additionally, we have not only the style properties used for the shorthand effect methods at our disposal, but also numeric CSS properties such as left
, top
, fontSize
, margin
, padding
, and borderWidth
. In Listing 4.5, we changed the text size of the speech paragraphs. We could animate this increase or decrease in size by simply substituting the .animate()
method for the .css()
method:
$(document).ready(function() { var $speech = $('div.speech'); var defaultSize = $speech.css('fontSize'); $('#switcher button').click(function() { var num = parseFloat($speech.css('fontSize')); switch (this.id) { case 'switcher-large': num *= 1.4; break; case 'switcher-small': num /= 1.4; break; default: num = parseFloat(defaultSize); } $speech.animate({fontSize: num + 'px'}, 'slow'); }); });
Listing 4.15
The extra properties allow us to create much more complex effects, too. We can, for example, move an item from the left-hand side of the page to the right-hand side while increasing its height by 20 pixels and changing its border width to 5 pixels. We will illustrate this complicated set of property animations with the <div id="switcher">
box. Here is what it looks like before we animate it:

With a flexible-width layout, we need to compute the distance that the box needs to travel before it lines up at the right-hand side of the page. Assuming that the paragraph's width is 100 percent, we can subtract the Text Size box's width from the paragraph's width. We have the jQuery's.outerWidth()
method at our disposal to calculate these widths, including padding and border. We'll use this method to compute the new left
property of the switcher. For the sake of this example, we'll trigger the animation by clicking on the Text Size label just above the buttons. Here is what the code should look like:
$(document).ready(function() { $('div.label').click(function() { var paraWidth = $('div.speech p').outerWidth(); var $switcher = $(this).parent(); var switcherWidth = $switcher.outerWidth(); $switcher.animate({ borderWidth: '5px', left: paraWidth - switcherWidth, height: '+=20px' }, 'slow'); }); });
Listing 4.16
It is worth examining these animated properties in detail. The borderWidth
property is straightforward, as we are specifying a constant value with units, just as we would in a stylesheet. The left
property is a computed numeric value. The unit suffix is optional on these properties; since we omit it here, px
is assumed. Finally, the height property uses a syntax we have not seen before. The +=
prefix on a property value indicates a relative value. So, instead of animating the height to 20 pixels, the height is animated to 20 pixels greater than the current height. Because of the special characters involved, relative values must be specified as a string, so must be enclosed in quotes.
Although this code successfully increases the height of the <div>
tag and widens its border, at the moment, the left
position appears unchanged:

We still need to enable changing this box's position in the CSS.
Positioning with CSS
When working with .animate()
, it's important to keep in mind the limitations that CSS imposes on the elements that we wish to change. For example, adjusting the left
property will have no effect on the matching elements unless those elements have their CSS position set to relative
or absolute
. The default CSS position for all block-level elements is static
, which accurately describes how those elements will remain if we try to move them without first changing their position
value.
Note
For more information on absolute and relative positioning, see Joe Gillespie's article Absolutely Relative at http://www.wpdfd.com/issues/78/absolutely_relative/.
In our stylesheet, we could set <div id="switcher">
to be relatively positioned:
#switcher { position: relative; }
Instead, though, let's practice our jQuery skills by altering this property through JavaScript when needed:
$(document).ready(function() { $('div.label').click(function() { var paraWidth = $('div.speech p').outerWidth(); var $switcher = $(this).parent(); var switcherWidth = $switcher.outerWidth(); $switcher.css({ position: 'relative' }).animate({ borderWidth: '5px', left: paraWidth - switcherWidth, height: '+=20px' }, 'slow'); }); });
Listing 4.17
With the CSS taken into account, the result of clicking on Text Size after the animation has completed will look like this:
