Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping

Posted September 28, 2011 at 11:00 AM by Ben Nadel

Tags: Javascript / DHTML

From what I have seen, the slideDown() method is perhaps one of the most used methods in jQuery. While the Sizzle library and the general jQuery API have revolutionized DOM access and manipulation, the slideDown() method has, in one stroke, allowed programmers to create a richer, more natural experience for their end users. Where user interfaces (UIs) used to feel mechanical, effects like the slideDown() function have helped them to feel "touchable" and user friendly. When you don't know how the the slideDown() method works, however, you can end up creating jumpy, jerky, and unexpected behavior.


 
 
 

 
  
 
 
 

No doubt, you've seen and maybe even coded a slideDown() effect where the final step of the animation was disproportionally large when compared to the smooth arch of the initial animation. This final "jump" in the exposure of the hidden content is due to a difference in height between what jQuery thinks the content will be and what it actually ends up requiring.

This delta in requirements is the result of the way in which jQuery calculates the height of the final, exposed content. Since hidden content has no offsets (height or width), jQuery has to actually make the content momentarily visible before it can calculate its height. And, in order to keep the user interface from jumping around, jQuery actually pulls the hidden content out of the document flow before making it "visible."

From what I have been told, it does this by temporarily changing the "position" of the hidden content to, "fixed." This new position behavior pulls the hidden content out of the document flow; however, the often-felt side-effect of this is that the hidden content is no longer constrained by the previous offset-parent (ie. the containing DOM node).

This difference in layout constraints is what causes the jumping in slideDown()-based animations. Once the hidden content has been pulled out of the document flow, its width may no longer be fixed. And, without a fixed width, we can easily end up with a different height.

To see what I'm talking about, take a look at the following code:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Using jQuery SlideDown() With Fixed Width Elements</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Using jQuery SlideDown() With Fixed Width Elements
  • </h1>
  •  
  •  
  • <!-- BEGIN: Container. -->
  • <div style="width: 300px ; border: 1px solid black ; padding: 10px ;">
  •  
  • Don't you want to
  • <a href="#" class="readMore">Read More</a>?
  •  
  •  
  • <!-- BEGIN: Hidden Content. -->
  • <div class="content" style="display: none ;">
  •  
  • This is where the additional content will go - the
  • content that the user can see when the Read More
  • link is clicked. We're going to use jQuery to slide
  • the content of this container into view, with a slow
  • transition. This is where the additional content will go
  • - the content that the user can see when the Read More
  • link is clicked. We're going to use jQuery to slide
  • the content of this container into view, with a slow
  • transition. This is where the additional content will go
  • - the content that the user can see when the Read More
  • link is clicked. We're going to use jQuery to slide
  • the content of this container into view, with a slow
  • transition. This is where the additional content will go
  • - the content that the user can see when the Read More
  • link is clicked. We're going to use jQuery to slide
  • the content of this container into view, with a slow
  • transition.
  •  
  • </div>
  • <!-- END: Hidden Content. -->
  •  
  •  
  • </div>
  • <!-- END: Container. -->
  •  
  •  
  • <script type="text/javascript" src="./jquery-1.6.3.js"></script>
  • <script type="text/javascript">
  •  
  •  
  • // Cache a reference to the hidden content.
  • var hiddenContent = $( "div.content" );
  •  
  • // Bind to the Read More link to toggle the
  • $( "a.readMore" ).click(
  • function( event ){
  •  
  • // Cancel the default event (this isn't a real link).
  • event.preventDefault();
  •  
  • // Check to see if the content is visible.
  • if (hiddenContent.is( ":visible" )){
  •  
  • // Hide it slowly.
  • hiddenContent.slideUp( 3000 );
  •  
  • } else {
  •  
  • // Show it slowly.
  • hiddenContent.slideDown( 3000 );
  •  
  • }
  •  
  • }
  • );
  •  
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see here, we have a container that has a fixed width of 300px. Inside this container, we then have a hidden content DIV that has no width constraints at all. And, if you watch the video above, you'll see an enormous jump in the slideDown() animation. This is due to the fact that height of the hidden content is extremely different based on the position of the hidden DIV. When the hidden content is not constrained to 300px - when it can spread across the entire browser window - it ends up taking significantly less vertical space:


 
 
 

 
 jQuery uses fixed-position elements to calculate height requirements in the slideDown() animation. 
 
 
 

In order to get rid of the jump at the end of the jQuery slideDown() animation, you have to make sure that the calculated height is the same as the final height. And, in order to do that, you have to make sure that the width of the hidden content is the same regardless of its position. The easiest way to do that is simply to add a fixed width to the hidden content.

  • <!-- BEGIN: Hidden Content. -->
  • <div class="content" style="display: none ; width: 300px ;">
  •  
  • This is where the additional content will go - the
  • content that the user can see when the Read More
  • link is clicked.....
  •  
  • </div>
  • <!-- END: Hidden Content. -->

Notice that our hidden DIV now has a fixed width of 300px - the same width it would be allocated if it was within the visible flow of the document. This will fix our animation completely.

jQuery's slideDown() method is awesome. But, in order to make sure that it always gives the same, rich, rewarding experience, it's important to understand how it works. And, once you do that, you can easily configure your code to remove all jumping or jerky motions from your slideDown() transitions.




Reader Comments

Sep 28, 2011 at 11:17 AM // reply »
2 Comments

Cool. Good info to have!


Sep 28, 2011 at 11:21 AM // reply »
4 Comments

TLDR: Ensure the container you are trying to slide down has a defined width. :)

Great write up dude.


Sep 28, 2011 at 11:30 AM // reply »
369 Comments

@Andrew,

Nice tip. I recently worked with jquery, and I think I had slidedown() as a part of it, but I do remember the container width coming into play at some point during manipulation. :-)


Sep 28, 2011 at 11:38 AM // reply »
211 Comments

Ben, great job explaining the issue. Makes perfect sense.


Sep 28, 2011 at 11:51 AM // reply »
11,238 Comments

@All,

Thanks guys. It's a problem that's bitten me a number of times. For a long time, I always just assumed it was jQuery messing up. Once someone told me (I wish I could remember who) how the height was calculated, it started to make much more sense where the jumping was coming from.

As a rule of thumb, I tend to try and "show/hide" containers that ONLY have a width (and sometimes height) on them. If I have borders and/or padding, I try to put those on an elements *within* the container being shown.


Sep 28, 2011 at 12:19 PM // reply »
369 Comments

@Ben, Thank you for the solution. If it happened with me, I would probably assume it was something with my computer messing up, like maybe not enough memory or something, as my computer messes up often and gives me all kinds of weird behavior. One thing that always got on my nerves when developing when first beginning was how when you develop a page and the page jumps around as it loads. Of course, that was WAY in the beginning. :-)

CSS has been a pain in my rear so far. If I could figure it out and become proficient with it, I am sure I would love it and it would lead to far more elegant solutions, and would probably make for better looking, designed, and coded sites. But front end development with UI's and what the user sees, and the whole aesthetic and design aspect of it is not my forte at all, and I can't tell you how much I have struggled with CSS. At one of my first development jobs, some of the design guys showed me how to use photoshop to design a site and cut it up, and during that time, table-less design was not all the rage, and it was still 100% acceptible and the standard of the industry to design sites using tables, so that is how I learned it, and that is what I learned. A dino like me is now having problems with this new trendy way of designing table-less web sites and using CSS. I know it is more elegant, better, etc., but it is very difficult to wrap your head around when you are used to doing the table stuff, and when that is how you learned it to begin with (and you aren't much of a design person at all). I continue to struggle with the CSS stuff.


Sep 28, 2011 at 1:28 PM // reply »
1 Comments

In the demo, you entered 300px as the width for the contained div, but the parent is 300px _and_ has a padding of 10px. So you probably want to enter 280px to account for the padding, don't you?

I'm guessing 300px worked because it gave the same number of lines but only as an accident.


Sep 28, 2011 at 1:53 PM // reply »
11,238 Comments

@Anna,

Yeah, CSS still feels very much like an art to me, not a science.

@Elisée,

Do to the box model, the 10px padding on the container should be *added* to the container's width. So, while it has an explicit width of 300px, its rendered width with padding and border should be 322px (300 + 10 + 10 + 1 + 1). The hidden content should then fit into the 300px width.... at least I think so. The box model is still something that throws me off :)


Sep 28, 2011 at 2:18 PM // reply »
369 Comments

@Ben, yeah, a lot of trial and error for me. An example is this box model stuff you are discussing with Elisee. I had no idea it worked that way. Good to know for future reference...

^ record shortest Anna comment ever.


Sep 28, 2011 at 2:48 PM // reply »
49 Comments

>> record shortest Anna comment ever.

Haha! Are you feeling ok? Might want to lie down for a bit until you recover. ;)

Ben: Just to confuse us all further, there's an alternative box model where you can specify the final width and the padding/etc is included within that size rather than appended to it. Not quite got full browser support yet, and I can't remember what it was called... flex or flux or similar.

If you're in a situation where you can't calculate width exactly (such as if padding is 1em or whatever), I suppose it would work to specify an approximate max-width value? So long as the value given is close enough, the final jump would be small enough not to be noticeable, right?


Sep 28, 2011 at 5:37 PM // reply »
369 Comments

@Peter,

yeah, I have a headache. Work has been extremely busy. But I am headed home now, thank goodness, and will be able to rest until tomorrow. :-) Can't quite tell you just how much this excites me. Sad, isn't it?


Sep 29, 2011 at 9:49 AM // reply »
4 Comments

Great! The video explanation and presentation made much easier to see and understand the problem and solution. Thanks Ben!


Sep 29, 2011 at 2:46 PM // reply »
369 Comments

I know CSS is the way to go, and tables not so much, but one thing that really did it for me with CSS was once when I was trying to do a table-less site, and the background WOULD NOT match up across the page. It woudln't fill in behind the content in one of my supposed "containers", thereby giving the bottom of my site an uneven background distribution. I had originally designed the thing using tables, but decided to try to be really smart and do the table-less thing, and I just simply could not get it to work. grrrrrr css. I had to revert back to tables. I would've had to completely change the design of the site otherwise.


Sep 29, 2011 at 4:49 PM // reply »
9 Comments

Great insight into a plaguing issue, thanks for that!

Now knowing the cause though, I can't help but wonder if it would be best for jQuery to take into consideration the width of the container of the content it's working with, seeing as how the way it's currently handled is a bit incomplete, it would appear.


Oct 1, 2011 at 7:20 AM // reply »
12 Comments

It seems like you can set the width automatically based on the parent before beginning the slide.

hiddenContent.width(hiddenContent.parent().width());


Oct 2, 2011 at 3:17 PM // reply »
8 Comments

Anna,

Something about layouts and tables for you

http://www.halhelms.com/blog/index.cfm/2010/10/28/CSS-Sanity-from-Zed-Shaw


Oct 3, 2011 at 10:18 AM // reply »
369 Comments

@Nando,

Thank you so, so, so much for that! It's not that I don't want to do things "right"...I absolutely do! It's just that I fall short on ability when it comes to some things, and I hate, hate, hate, hate rigging and doing things "the wrong way", but sometimes I either get into a time crunch, or I reach a point to where it's just like hitting my head against a brick wall, and I really at that point have no choice other than to "rig" and do things in a way that is other than ideal. Thank you so much for the link...I will thoroughly enjoy reading that. I absolutely love you guys and how helpful you are. You are awesome!


Oct 3, 2011 at 11:13 AM // reply »
1 Comments

Thanks for this! It's been bothering me for a long time.


Oct 3, 2011 at 1:02 PM // reply »
369 Comments

@Nando,

I got a chance to read over the information you posted from the link earlier...again, thank you very much...and also, I clicked through to the link he was referencing as well. I loved that material. It was awesome. I was laughing 70% of the time (at least) as I was reading, and most of the time I was reading it, I was nodding my head in agreement and remembering back to specific instances where I had struggled in the same way. I particularly love this quote by him:

  • My first problem with CSS is simply that it just never does what you tell it to. I say, "make this a column CSS" and it goes, "What? No that should go over here totally on the left and f--- you I like apples." I say, "make this fill all of the parent div" and CSS says, "Sharks love tiny needles, and no that will only take up the top part." I say, "Hey, CENTER THIS" and CSS says, "My shoes have centered worms but your heading will stay to the left."

and also

  • Seriously, in 20 years, when the world looks back on us, they'll wonder why the f---we struggled for decades with something so f---ing weird.

A good read for my Monday. :-) I think part of my problem is that with programming, I enjoy procedural program to a certain degree, and I appreciate a logical order to things. So far, working with CSS simply hasn't been logical...at all. The aforementioned way of doing things seemed a whole lot more logical and to have an order that made a whole heck of a lot more sense. Now, that being said, I am not expert on CSS, and it is quite possible that there are guys out there who can do CSS, and it is completely logical to them, I just don't get it. Yet. I may someday, though. We'll see.


Oct 29, 2011 at 9:11 PM // reply »
11,238 Comments

@Jon,

Cool my man - glad you liked :)

@JGarrido,

That's an excellent question. In all my thinking about why this happened, I never really stopped to think about "should" this happen. I wonder if there is something that jQuery can do about it; or, would checking the parent lead to other issues that we're not thinking about?

@Tom,

That could be a good option. Getting heights / widths of elements always makes me a bit nervous 'cause I am never sure how paddings and borders getting taken into account. But, that's just fear talking.

@Kory,

Awesome! I'm glad this helped clear it up. I had this problem for a long time as well.


Nov 11, 2011 at 2:05 PM // reply »
6 Comments

hi ben!

thanks for the detailed explanation. this makes a whole lot of sense.


Nov 17, 2011 at 8:47 PM // reply »
11,238 Comments

@Chris,

Cool my man, glad you found this helpful.


Dec 24, 2011 at 8:37 AM // reply »
6 Comments

Nope.
Not fixed.
jquery changes/forces those (copy-paste from source):
cssShow = { position: "absolute", visibility: "hidden", display: "block" },

That flickering you see may be caused by margins. By definition margins collapse - so when box A has margin-bottom 20px and box B below A has margin-top 10px, then collapsed margin/distance between them is 20px, not 30px. Slidedwon animates height, padding and margins. So my advice would be to NOT use top, bottom margins on slided content and you should be fine. Use padding on outer container when space is needed instead.


Feb 11, 2012 at 9:29 PM // reply »
1 Comments

I can't say how glad I am that I found your post.
Thank you very much.


Feb 12, 2012 at 11:50 AM // reply »
1 Comments

Below is the code I am using to prevent jerky sliding of the div, div3. Would you please help me in fixing this issue? The code works well in FireFox, but the div that is hidden/show jerks in IE8. Thank you very much in advance for your help!!

<!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>
<style>
.div3{
width: 300px;
height:40px;
}
.div4{
width: 300px;
height:80px;
}
</style>

<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript">

$(document).ready(function(){

$('[value="myDiv_3"]').attr('checked',true);
$('.div3').show();

$('input[name="myRadio"]').change(function(){
var selected = $(this).val();
$('.div3').slideUp();
$('#'+selected).slideDown();
});
});
</script>
</head>

<body style="text-align:center;">
<form action="example.com" method="post">
<input type="radio" name="myRadio" value="myDiv_3" />MyDiv3
<input type="radio" name="myRadio" value="myDiv_4" />MyDiv4
</form>
<div id="myDiv_3" class="div3">Div number 3!</div>
<div id="myDiv_4" class="div4">Div number 4!</div>
</body>
</html>


Feb 23, 2012 at 2:06 AM // reply »
1 Comments

Hey man, works great! Thank you so much. This has been bugging me for a while!

-Brendan


Nov 8, 2012 at 10:26 AM // reply »
1 Comments

Just an additional quick thank you for the thorough explanation. Solved my animation problem in a snap.


Mar 12, 2013 at 11:07 AM // reply »
1 Comments

Hi! I know it's an old post, but I have this problem today with a little issue extra: I didnt know the element width.
So, after undestanding the problem thanks to your explanation, Ben, I came out with this solution to my problem, that may be useful for others.

Here it gooes:

function slideFix(block, interval){ // Element to hide, interval value (int)
block.width(function(){
return block.parent().innerWidth();
}, block.slideToggle(interval).delay(interval+1).width('auto'));
}

Maybe not the best solution, but works perfect for me.

Thanks!



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 19, 2013 at 2:31 PM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
It's funny really just how well that image describes the way I would imagine most people that go with angular for some project is. I have had a similar roller-coaster ride with it as well, but not qu ... read »
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools