Watch
Watch Animation Jump Revisited screencast (Alternative flash version)
QuickTime version is approximately 20Mb, flash version is streaming.
View the demo used in the screencast
Understanding the Problem
Similarly to before the animation would jump when it gets towards the end. However, this time the problem can’t be fixed by moving the padding around.
The problem is actually due to an incorrect height being determined, which is triggered by a number of factors. The element being animated…
- Doesn’t have a predefined width, and in the document it is inheriting the width from a parent element.
- Is changed to
position: absoluteand as such the margins around the top and bottom no longer collapse. This is to determine the height by bringing it back in to view (whiles havingvisibility: noneset) but not affecting the flow of the page.
As you’ll see in the screencast, just setting a width doesn’t quite get the correct height.
So we can’t just use CSS to fix the jump, we need to write slightly different jQuery.
Fixing the Problem
The task requires us to:
- Grab and store the initial height before hiding the element
- Set an inline height to prevent the first reveal from jumping
- If we are revealing, and the element is visible, animate to zero height and then hide
- Otherwise, show and animate the height to the initial captured height
var $div = $('#test');
var height = $div.height();
$div.hide().css({ height : 0 });
$('a').click(function () {
if ( $div.is(':visible') ) {
$div.animate({ height: 0 }, { duration: 2500, complete: function () {
$div.hide();
}
});
} else {
$div.show().animate({ height : height }, { duration: 2500 });
}
return false;
});
Wrapping Up
I’m going to post a bug on the jQuery dev site, and I’ve had a play around the code to be able to accurately establish the height of a hidden element - it’s not easy.
Hopefully this might be one of the last times we run in to the jump problem!
You should follow me on Twitter here I tweet about jQuery amongst the usual tweet-splurges!
Related screencasts
Demo
If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.
Source Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Animation Jump - version 2</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { background-color: #fff; font: 16px Helvetica, Arial; color: #000; font-size: 16px; line-height: 20px; padding: 20px; }
a { line-height: 40px; }
#container { width: 400px; }
#test { background: #c00; color: #fff; }
#test p { margin: 0; margin-bottom: 16px; }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function () {
var $div = $('#test');
var height = $div.height();
$div.hide().css({ height : 0 });
$('a').click(function () {
if ($div.is(':visible')) {
$div.animate({ height: 0 }, { duration: 2500, complete: function () {
$div.hide();
} });
} else {
$div.show().animate({ height : height }, { duration: 2500 });
}
return false;
});
});
</script>
</head>
<body>
<div><a href="#test">reveal</a></div>
<div id="container">
<div id="test">
<p>Hello from JS Bin</p>
<p id="hello">this is another content block - but it's going to jump when it's exposed :-(</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
</body>
</html>

Play QuickTime version
Play Flash version

Steve Radford On 21st June 2009 at 20:06
I’m currently using: http://pastebin.com/m3a08793 to toggle several different spans on one page using different anchors. For now I have assigned the height in the CSS however it is still jumping a little. I’ve tried implementing the fix highlighted in this tutorial and I cannot work out how to get it to work with multiple elements.
retro_boy78 On 30th June 2009 at 22:06
hi guys, i would like to thank the developer who created this script…i had been looking for this kind of script for a while and i’m glad i checked out jquery…
i hope someone can help me about implementing this script to an existing div (content)…i seem to have a problem testing the code when i am loading the script within my content div…basically the “containerslide” div that goes into my content div i think is messing up the coding…it does not slide down the text in the block at all…but when i preview the sample file on it’s own, the slide down text shows/hide…i am loading the page in a “no reload” page (my index page), meaning the header and menus does not refresh…
is there a reason why the slide down effect does work when i call it to load in my content div? or is there something more behind the errors? i can supply the code i used to build my sample if you are willing to look at it…
i really need your help, your input would be greatly appreciated…
thank you!
Clark On 23rd July 2009 at 03:07
In the code sample
style="display:none"is omitted.Michael On 3rd August 2009 at 02:08
Thanks for the tip to solving this problem. The only additional note I have is that you need to add in top & bottom padding into the animation toggling between values “hide” (zero did not work for me) and “show”. Looking at the jQuery code for slideDown they also have margin toggling as well (although I didn’t require it for my situation). After that alteration your code worked perfectly for me.
jQuery 1.3.2, Fx 3.5.1
P.S. Love the mod that delays comments from being displayed for 10mins allowing last minute alterations.
Scott B On 26th August 2009 at 23:08
Brilliant discovery. Too bad the solution requires so much fugging code just to smooth out. Hope this gets squashed with a bug release soon!
Big On 1st September 2009 at 21:09
I was looking for a tut on how to do this with ajax calls in stead of inline content. Are you up for one of those?
Eric D. Fields On 7th October 2009 at 18:10
Thanks for this info. Running into this right now using jQuery 1.3.2
Trying to do a slideToggle() on a after you click its . With no custom margin or padding, I still get a jump.
According to http://jqueryfordesigners.com/animation-jump-quick-tip/, this should have been fixed in jQuery 1.3.2? Still going to do your height-grabbing method, much to my dismay :-/
Hilco On 20th October 2009 at 19:10
way to extensive :) just add a width and a padding-bottom of 10px using css.
3dealism On 29th October 2009 at 17:10
Yeah, that Code is nice and works, but what have I to modify to get it work with more than one sliding div without sliding all divs at once???
Ben Nadel On 30th October 2009 at 16:10
A most excellent tip! I did not know that it changed the position to absolute to calculate the height. I just changed the structure slightly to use a width and the animation jump (for me, it was popping up slightly at the end of the animation) was gone!
Thank you very much.
Satinafield On 3rd November 2009 at 17:11
Hi,
Thanks for the great tutorial
I have added the .click function to a check box, which triggers the slide but does not show the tick in the check box, anyone got idea why this is happening?
Thanks
Richard On 16th December 2009 at 11:12
Thanks for explaining the reasons behind the jumpy animation. It makes sense to me now. I was trying to make a small ‘accordian’ type plugin when I came across this issue. As I was dealing with multiple blocks, I used data() to store the individual section heights before hiding the sections, and then used that same value for animating the heights. It all works beautifully now without any jumps in the animation. :)
[edit: didn't see previous comments, same solution!]Jake Moore On 20th January 2010 at 09:01
Hey there, This is a great tutorial, and you go into great detail. I love this bit of code you’ve shown us, but I’ve found a problem with it. I have other links on my page that jump to certain areas of the page next to my SlideDown link (ex: <a href=”#about”> and <a href=”#team”>). However, instead of jumping to their respective parts of the page, they all open the SlideDown. Does anyone know how to fix this?
Actually, every link on the page that has a # in it opens the drawer. That is definitely not the desired effect >.<
Thank you,
-Jake Moore
Benjamin Welch On 10th February 2010 at 23:02
Hey Remy,
I’m a freelance web & graphic designer and I just wanted to say that I would have ripped my hair out, squeezed lemon juice into my paper cut eyes and cried like a baby if you hadn’t made parts jQuery understandable to a beginner.
Your work is much appreciated. I’ll spread the word and if there’s anything else I can do to help, let me know.
Thanks again.
Jared Christensen On 13th March 2010 at 09:03
Setting the container div’s position to relative seams to be fixing the width problem for me.
Ben Goevaerts On 7th April 2010 at 13:04
@Mike Taylor: Can you give some more info please?
I’m still trying to get more elements in one page …
Great website btw;
Bfred On 12th April 2010 at 16:04
Nice post, I came across this problem on this website: http://www.hotelteti.com/a/new/it/listino/ But since the content of that “div” is dynamic this method doesn’t work for me. So apparently this works: