treehouse : what would you like to learn today?
Web Design Web Development iOS Development

Animate Height/Width to “Auto”

Last updated on:

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

View Comments

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.

Leave a Comment

Use markdown or basic HTML and be nice.