Grow your CSS skills. Land your dream job.

Last updated on:

Animate Height/Width to “Auto”

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); 
});

Reference URL

Comments

  1. Colton
    Permalink to comment#

    If you are experiencing a resize issue, where the element is (when resized) bigger than it’s parent, replace:

    .appendTo("body");

    with:

    .appendTo(el.parent());
  2. Permalink to comment#

    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:

    
    var refheights = [];
    
    $(document).ready(function(){
        setTimeout(function(){
            $('.these').children('div').each(function(e){
                refheights[e] = $(this).height();
            });
        },500);
    });
    

    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.

    
    $(this).animate({'height':refheights[($(this).index())-1]}, 800);
    

    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:

    
    <div class="wrapper">
        <div class="content"></div>
    </div>
    
    
    .wrapper{
        overflow:hidden;
        height:178px;
    }
    

    then animate the wrapper to the height of the interior element, and it appears to be animating to the given height – dynamically:

    
    $('.wrapper').animate({'height':$('.content').height()},800);
    

    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.

  3. Steve
    Permalink to comment#

    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.

    • Darryl

      Steve you wonderful man you!

      Max-height just rocked my world in a good way. Couldn’t have been easier.

      Thanks!

    • Steve

      Not a problem. Glad it helped!

    • Austin Crane
      Permalink to comment#

      Had to comment on the EASY approach! Thank you so much!

    • Ben
      Permalink to comment#

      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.

      function toggleHorizontal(hidden_id, click_id){
          if($('#'+hidden_id).css('max-width') == "0px"){
              $("#"+hidden_id).animate({"max-width":"350px"}, 300);
              $("#"+click_id).html('&raquo;');
          }else{
              $('#'+hidden_id).animate({"max-width":"0px"}, 300);
              $("#"+click_id).html('&laquo;');
          }
      }
      

      Then just set the div to max-width: 0px; initially, apply onclick="toggleHorizontal('hidden_id', 'click_id')" and bazinga! Hopefully someone finds this as helpful as I found Steve’s suggestion.

    • Rob
      Permalink to comment#

      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!

  4. Robert
    Permalink to comment#

    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).

  5. Chris
    Permalink to comment#

    You are amazing!

  6. Steve, this is genius. Thanks Chris for highlighting that, you’re on the ball.

  7. StepanVich
    Permalink to comment#

    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 ??

  8. Permalink to comment#

    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.

  9. 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. ^_^

        $.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"}).insertAfter(this);
            height = elem.css("height"),
            width = elem.css("width"),
            elem.remove();
    
            if (prop === "height"){
                el.animate({"height":height}, speed, function(){
                    $(this).css({height: 'auto'});
                    if (typeof callback !== 'undefined') {
                        callback();
                    }
                });
            }
            else if (prop === "width") {
                el.animate({"width":width}, speed, function(){
                    $(this).css({width: 'auto'});
                    if (typeof callback !== 'undefined') {
                        callback();
                    }
                });
            }
            else if (prop === "both"){
                el.animate({"width":width,"height":height}, speed, function(){
                    $(this).css({width: 'auto', height: 'auto'});
                    if (typeof callback !== 'undefined') {
                        callback();
                    }
                });
            }
        });
    };
    
  10. David Clark
    Permalink to comment#

    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.

  11. Balamurugan
    Permalink to comment#

    Thanks a lot Steve. You saved my day

Leave a Comment

Posting Code

  • Use Markdown, and it will escape the code for you, like `<div class="cool">`.
  • Use triple-backticks for blocks of code.
    ``` 
    <div>
      <h1>multi-line block of code</h1>
      <span>be cool yo.</span>
    </div>
    ```
  • Otherwise, escape your code, like <code>&lt;div class="cool"&gt;</code>. Markdown is just easier though.

Current ye@r *

*May or may not contain any actual "CSS" or "Tricks".