It’s not possible to do thing.animate({ "height": "auto" });
. So this is Darcy Clarke’s method to allow that to work. You essentially clone the element, remove the fixed heights currently inflicting the element, and measure/save the value. Then you animate the real element to that value.
jQuery.fn.animateAuto = function(prop, speed, callback){
var elem, height, width;
return this.each(function(i, el){
el = jQuery(el), elem = el.clone().css({"height":"auto","width":"auto"}).appendTo("body");
height = elem.css("height"),
width = elem.css("width"),
elem.remove();
if(prop === "height")
el.animate({"height":height}, speed, callback);
else if(prop === "width")
el.animate({"width":width}, speed, callback);
else if(prop === "both")
el.animate({"width":width,"height":height}, speed, callback);
});
}
Usage
$(".animateHeight").bind("click", function(e){
$(".test").animateAuto("height", 1000);
});
$(".animateWidth").bind("click", function(e){
$(".test").animateAuto("width", 1000);
});
$(".animateBoth").bind("click", function(e){
$(".test").animateAuto("both", 1000);
});
If you are experiencing a resize issue, where the element is (when resized) bigger than it’s parent, replace:
with:
If you are trying to animate the height on inline elements (like a paragraph), you’ll want to make sure you aren’t changing the width to auto as well. You’ll want to change this line:
to:
A paragraph is a block element.
as much as I want this to work, I’ve now run into two separate instances where using this doesn’t work. the logic is entirely there – cloning, checking, then animating – but for whatever reason, it’s frustratingly stubborn for me. I either get heights that are way too big, or way too small. I’ve subsequently found two workarounds for this:
the first is to let the content load naturally, grab the heights after the page has loaded, then immediately add a class that would ‘resize’ the box to the desired height. it looks something like this:
the setTimeout lets the web fonts load before taking the heights: it turns out those don’t get loaded until the very end in some browsers, and will give false readings. this also works for positions, similarly avoiding the same pitfall with the setTimeout. then, when the time comes to utilize the heights, simply animate to the given value in the array.
if you can’t assign an index to the element, or if the elements’ content is dynamic, simply give the item you’d like to animate a wrapper, and set it’s overflow to hidden:
then animate the wrapper to the height of the interior element, and it appears to be animating to the given height – dynamically:
I’m sure there are better ways programmatically to go about both of these, but they have worked marvelously for me.
oh, and much love to this site. I hope to one day buy you a beer, Mr. Coyier.
There is an easier way most of the time.
Instead of trying to animate height, animate max-height.
When you want it hidden, max-height:0px does the trick, and when you want it shown, you can animate it to max-height:10000px;…. it will then animate to its normal height.
Just make sure you use max-height instead of height in your transition declaration.
Steve you wonderful man you!
Max-height just rocked my world in a good way. Couldn’t have been easier.
Thanks!
Not a problem. Glad it helped!
Had to comment on the EASY approach! Thank you so much!
Love it – thanks, Steve!
Here’s some simple jQuery I used with max-width to display a menu in a div with onclick. Keep in mind that any padding on the element you’re adjusting will cause that much of the element to show. Which for my purposes was good (it allowed the ‘«’ and ‘»’ you see in my code to display, which is what the user is clicking to show/hide the menu) but if you don’t want that then be sure to add some extra coding to add/remove your padding.
Then just set the div to
max-width: 0px;
initially, applyonclick="toggleHorizontal('hidden_id', 'click_id')"
and bazinga! Hopefully someone finds this as helpful as I found Steve’s suggestion.However, when the height is small, the animation will have a serious delay. Knowing what the height is makes the animation more consistent.
Wow Steve, you just made my day! I can’t believe I’ve never heard of this method, it works perfectly. Thanks!
Steve , you are so awesome!
Love you now.
Hello,
someone had alike problem and to solve it I just wrote on stackoverflow
http://stackoverflow.com/questions/1472303/jquery-get-width-of-element-when-not-visible-display-none/12114088#12114088
The problem with our copy and paste it to the body is, that the real width and height could be something else, so it depends really on the CSS context (CSS-DOM position), if you paste it directly to body, the DOM-Element colud be out of some parent CSS rules.
I do not any robust solution, which could solve this issue. So I will have a further look at Shadow-DOM (perhaps this can make it robust).
Steve, this is genius. Thanks Chris for highlighting that, you’re on the ball.
Hi I have problem with this script !! When i add it into my website i always get this Error: Object [object global] has no method ‘each’. Error is maybe on line 3. Do you have any idea how it solve ??
Stepan, did you include JQuery into your script?
I’ve used your code. Thank you!
I had to make changes to resolve a general concern.
Imagine certain styles aren’t appplied to the cloned element if it is in the body, than if it is in the original’s location (say a style onyl applied through a parent element’s class).
To solve this, I appended the clone to the parent of the original. To prevent an edge-case flash of the clone element, I added
"visibility":"hidden"
to the method.css(...)
.I also did
.removeAttr("id")
on the cloned element may have to prevent other plugins acting on the element from acting on the clone. This could be an paramater option, becuase perhaps you want the element to stay in sync with whatever plugin is acting on original via id.Thank you again for solving my problem with your code.
Hi,
Why clone the element to get height, would it not be simpler (and faster?) to temporarily position (and show) the element way out left in it’s relatively positioned parent? For example by adding a class like this to the element:
Several issues with the original code.
First, the elements a animated to the desired ‘auto’ height or width, correct, but at the end, the height or width is fixed. So if content of the element grow, it doesn’t accommodate properly when it should be when css height or width is set to ‘auto’.
Second, clone element is always appended to ‘BODY’. Depending on your DOM CSS styles, it may or may not be what you intended it to be at the DOM location.
I’ve made some modifications to the code to ‘fix’ those problems.
First problem is fixed by adding a line to set the css to ‘auto’, as in the case of ‘width’:
$(this).css({width: 'auto'});
, after animation is completed.Second problem is fixed by
.insertAfter()
the original element instead of.appendTo()
the BODY, where the context of which may not render the desired ‘auto’ height or width. However, there is still a limitation of this fix depending on your CSS. But I expect that should happen only rarely.Anyway, thanks for sharing the code though, it saves me some time writing it myself. ^_^
If anybody finds themselves at the bottom of these comments —- I’m trying to create a reliable solution for this all-too-common problem that’s up on Github, not just in a comment or a blog post.
https://github.com/davidtheclark/jquery.animateAuto
I believe I’ve incorporated the ideas people have shared above, as well as my own — and I’m hoping others want to contribute to developing a totally solid, reliable, and reusable solution. Let’s pool efforts.
Thanks a lot Steve. You saved my day
The function animateToAutoHeight work well.
http://stackoverflow.com/questions/5003220/javascript-jquery-animate-to-auto-height
Steve, you’re awesome.
wow..
it’s mean.. i’m am the same level of expert :P
I just coded the same thing. and just to know how people are coding to get this result, and I found you .. :) you coded the same ..
does it mean i am a good coder or you are not good like me :)
thanks
Thank you very much for this code. You saved my life
Seems the clone causes some issues due to its positioning in the DOM/CSS DOM. Made a couple small changes to the script to ensure you always get the “auto” height and width by simply using the original element in place. Might be helpful for someone. Oh, also added some logical defaults for prop, speed, and callback.