Wednesday, December 16, 2009

Simple Effects Plugins

Simple Effects Plugins:

jQuery has a nice selection of core animation effects, such as .show('speed') and .hide('speed'), .slideUp() and .slideDown(), and .fadeIn() and .fadeOut(). It even has a couple methods for toggling effects — the aptly named .toggle('speed') and .slideToggle().

All of these methods have optional speed, easing, and callback arguments — although a couple are special cases. The .show() and .hide() methods, when used without a speed, will immediately show and hide the matched set of elements with no animation. When the speed argument is included, the matched elements are shown and hidden gradually by animating their height, width, and opacity simultaneously. The .toggle() method shares its name with a method that takes two arguments that alternate being triggered. All of the other effect methods have a default speed of 400ms.

The Flexible .animate()

jQuery internally uses another method, .animate(), to define these shorthand effect methods, and it makes .animate() available to us to do the same. So, let's create our own method that we can use the same way we would use, for example, .slideToggle().

Custom Animation Methods

Someone on the jQuery discussion list recently asked if there was a .fadeToggle() effect in jQuery. In my reply, I admitted that there wasn't one, but suggested that it wouldn't be too hard to create using .animate(). We just attach .fadeToggle to jQuery.fn and pass in the speed, easing, and callback arguments. Then, we return this.animate() with the effect we want, along with those same arguments:

JavaScript:
  1. jQuery.fn.fadeToggle = function(speed, easing, callback) {
  2. return this.animate({opacity: 'toggle'}, speed, easing, callback);
  3. };

Now, when we want to use it, we can treat it the same as any other jQuery method. For example:

JavaScript:
  1. $(document).ready(function() {
  2. $('#fade').click(function() {
  3. $(this).next().fadeToggle('slow');
  4. });
  5. });

Try it out:

Fade Toggle
Watch me fade.

(Incidentally, Dan G. Switzer saw the discussion-list thread and blogged about it himself. Thanks, Dan!)

To create a method that toggles a fade and a slide at the same time, all we need to do is repeat the process, adding a 'height' parameter:

JavaScript:
  1. jQuery.fn.slideFadeToggle = function(speed, easing, callback) {
  2. return this.animate({opacity: 'toggle', height: 'toggle'}, speed, easing, callback);
  3. };

Give this one a try:

Slide-Fade Toggle
Watch me slide and fade.

Blind Toggle

Let's try one more — a "blind" effect. Instead of changing the height of the element, as we do with a "slide" animation, we're going to move the entire element up and down.

The plugin itself will still be fairly rudimentary, but we'll need to set up some CSS to get it to work correctly. Here is the CSS:

CSS:
  1. #box {
  2. padding: 10px;
  3. height: 100px;
  4. width: 100px;
  5. background: #e459e9;
  6. }
  7. #box-outer {
  8. overflow: hidden;
  9. height: 120px;
  10. margin: 20px;
  11. }

Notice that we have two 'boxes' styled here. The first one will be in the markup itself, but the second one, since it's only being used to help with the effect, will be created by our script. The important properties here are #box-outer's overflow: hidden and height: 120px. The hidden overflow will allow #box to seemingly disappear as it moves up, while the height (which is #box's height plus its top and bottom padding) will keep the rest of the page from shifting along with the box.

Now, on to the plugin code:

JavaScript:
  1. jQuery.fn.blindToggle = function(speed, easing, callback) {
  2. var h = this.height() + parseInt(this.css('paddingTop')) + parseInt(this.css('paddingBottom'));
  3. return this.animate({marginTop: parseInt(this.css('marginTop')) < 0 ? 0 : -h}, speed, easing, callback);
  4. };

While relatively simple, there are a couple things here that might be confusing to jQuery/JavaScript beginners. The first line inside the function declares a variable for the height of this, plus the top and bottom padding ('this' here refers to whatever is matched by the selector in the script that uses the plugin). The parseInt() JavaScript function function looks at a string from left to right until it encounters a non-numeric character. The string of digits up to that character is converted into an integer, stripping off the trailing non-numeric character. So, '10px' becomes 10.

The line that follows animates the marginTop property. It uses a ternary (conditional) operator to test if marginTop is less than zero. If it is, the element's marginTop property animates to 0; if not, it animates to negative the value stored in the h variable.

Finally, we're ready to put this plugin to use:

JavaScript:
  1. $(document).ready(function() {
  2. var $box = $('#box')
  3. .wrap('<div id="box-outer"></div>');
  4. $('#blind').click(function() {
  5. $box.blindToggle('slow');
  6. });
  7. });

Line 2 'caches' our selector, since we're using it more than once. Then we wrap a div around the '#box' div and bind a click handler to a button. Let's see how this one looks:

Blind Toggle

Blind me up. Blind me up. Blind me up.

So, now we have three simple effects methods that we apply to our sites for a little extra flair.

Enchant

For really cool effects, check out the brand new jQuery Enchant — a set of effects similar to the popular script.aculo.us effects for Prototype. While Enchant is still only in an Alpha version, it already looks fantastic.