Pew Pew Laser Blog

Code. Glass art. Games. Baking. Cats. From Seattle, Washington and various sundry satellite locations.

Pew Pew Laser Blog Archives — by Blog ID

Smooth Animation Using jQuery's slideToggle().

2.18.2009

I finally found a solution to a jQuery problem that had been bothering me for nearly six months - the dreaded jumping animation. Here is a simple definition list, where visibility of the definitions is animated using jQuery's slideToggle() function.

Bat Cupcakes
These are a simple chocolate cupcake, with a dusting of powdered sugar for a topping. The bat and ghost shapes were made by placing paper cut-outs over the cupcake before dusting on the powdered sugar.
Jam Cookies
Start with a tube of premade sugar cookie dough. Press a cookie-sized amount into mini-muffin pans and then bake as directed. Dust the cookie cups with powdered sugar. Microwave some jam (raspberry and mint) and spoon it into the cookie cups. Melted some chocolate chips, scoop them into a platic baggie, cut off the corner of the baggie, and drizzle the chocolate on the cookies.
Chocolate Sprinkle Cupcakes
These are chocolate cupcakes, with a cream-cheese frosting, and fall-themed harvest leaf sprinkles.

In the previous version, the elements would jump a bit near the end of the animation as they were closing. With jQuery version 1.2.x, the most popular solution for this was to remove all padding and margin on the animating elements, as it was known that jQuery wouldn't animate them. jQuery v1.3 now animates margin and padding, but simply upgrading to the newest jQuery library did not fix my problem.

I noticed that my animation jumps occurred only when the animating elements or any of their parents had a width specified. The final fix came via Fen's comments on "Animation Jump - quick, tip" at jqueryfordesigners.com. I store the height of all dd before they are initially hidden, and the re-apply the height just before slideToggle()'s hiding animation.

To make the script flexible enough to handle new elements added to the definition list, I stored each element's widths in an array, and then retrieved the appropriate width based on the definition's position in the list. Here is my finished code:

 $(document).ready(function(){

	//  Get height of all dds before hide() occurs.  Store height in heightArray, indexed based on the dd's position.
	heightArray = new Array();
	$("dl.v_show_hide dd").each(function(i) {
	  theHeight = $(this).height();
	  heightArray[i] = theHeight;
	});

	// Hide all dds
	$("dl.v_show_hide dd").hide();

	//  When a dt is clicked, 
	$("dl.v_show_hide dt").click(function () {
	  //  Based on the dt's position in the dl, retrieve a height from heightArray, and re-assign that height to the sibling dd.
	  $(this).next("dd").css({height: heightArray[$("dl.v_show_hide dt").index(this)]});
	  //  Toggle the slideVisibility of the dd directly after the clicked dt
	  $(this).next("dd").slideToggle("slow")
		//  And hide any dds that are siblings of that "just shown" dd.
		.siblings("dd").slideUp("slow");
	});

 });

I suspect that what I encountered is a jQuery bug - that when a parent width specification exists, the animating element's height is not calculated correctly when animating to non-visible using slideToggle().

Permalink

Tags: code javascript jquery

Authorized users may log-in to leave a comment.

Last Blog: My Kind of Stick People.

Next Blog: Unimpressive.