Animate element to auto height with jQuery

192,853

Solution 1

  1. Save the current height:

    var curHeight = $('#first').height();
    
  2. Temporarily switch the height to auto:

    $('#first').css('height', 'auto');
    
  3. Get the auto height:

    var autoHeight = $('#first').height();
    
  4. Switch back to curHeight and animate to autoHeight:

    $('#first').height(curHeight).animate({height: autoHeight}, 1000);
    

And together:

var el = $('#first'),
    curHeight = el.height(),
    autoHeight = el.css('height', 'auto').height();
el.height(curHeight).animate({height: autoHeight}, 1000);

Solution 2

IMO this is the cleanest and easiest solution:

$("#first").animate({height: $("#first").get(0).scrollHeight}, 1000 );

Explanation: The DOM already knows from its initial rendering what size the expanded div will have when set to auto height. This property is stored in the DOM node as scrollHeight. We just have to fetch the DOM Element from the jQuery Element by calling get(0) and then we can access the property.

Adding a callback function to set the height to auto allows for greater responsiveness once the animation is complete (credit chris-williams):

$('#first').animate({
    height: $('#first').get(0).scrollHeight
}, 1000, function(){
    $(this).height('auto');
});

Solution 3

This is basically the same approach as the answer by Box9 but I wrapped it in a nice jquery plugin that takes the same arguments as a regular animate, for when you need to have more animated parameters and get tired of repeating the same code over and over:

;(function($)
{
  $.fn.animateToAutoHeight = function(){
  var curHeight = this.css('height'),
      height = this.css('height','auto').height(),
      duration = 200,
      easing = 'swing',
      callback = $.noop,
      parameters = { height: height };
  this.css('height', curHeight);
  for (var i in arguments) {
    switch (typeof arguments[i]) {
      case 'object':
        parameters = arguments[i];
        parameters.height = height;
        break;
      case 'string':
        if (arguments[i] == 'slow' || arguments[i] == 'fast') duration = arguments[i];
        else easing = arguments[i];
        break;
      case 'number': duration = arguments[i]; break;
      case 'function': callback = arguments[i]; break;
    }
  }
  this.animate(parameters, duration, easing, function() {
    $(this).css('height', 'auto');
    callback.call(this, arguments);
  });
  return this;
  }
})(jQuery);

edit: chainable and cleaner now

Solution 4

A better solution would not rely on JS to set the height of your element. The following is a solution that animates a fixed height element to full ("auto") height:

var $selector = $('div');
    $selector
        .data('oHeight',$selector.height())
        .css('height','auto')
        .data('nHeight',$selector.height())
        .height($selector.data('oHeight'))
        .animate({height: $selector.data('nHeight')},400);

https://gist.github.com/2023150

Solution 5

this is working and it is simplier then solutions before:

CSS:

#container{
  height:143px;  
}

.max{
  height: auto;
  min-height: 143px;
}

JS:

$(document).ready(function() {
    $("#container").click(function() {      
        if($(this).hasClass("max")) {
            $(this).removeClass("max");
        } else {
            $(this).addClass("max");
        }

    })
});

Note: This solution requires jQuery UI

Share:
192,853

Related videos on Youtube

Daniel
Author by

Daniel

Updated on September 23, 2020

Comments

  • Daniel
    Daniel over 3 years

    I want to animate a <div> from 200px to auto height. I can’t seem to make it work though. Does anyone know how?

    Here’s the code:

    $("div:first").click(function(){
      $("#first").animate({
        height: "auto"
      }, 1000 );
    });
    
    • kleinfreund
      kleinfreund almost 10 years
      You should mark the best answer as accepted.
    • Ian Mackinnon
      Ian Mackinnon about 9 years
    • Madara's Ghost
      Madara's Ghost about 9 years
      @IanMackinnon this question certainly has better answers. I've closed that question as a duplicate of this.
  • Katya Appazova
    Katya Appazova about 13 years
    this is not gonna work your var height is just accessible inside the ready function.
  • David Tang
    David Tang about 13 years
    @Daniel, where is your JS code? Post that bit, and also parts of the HTML that show the elements you refer to.
  • EMMERICH
    EMMERICH about 13 years
    Ah. Well, it seems you've discovered the solution. For safety, I'd still use $(this) inside your click handler.
  • Prakash
    Prakash about 13 years
    define the height before the ready function, and use only height than var height.. this way it may work daniel
  • jinyong lee
    jinyong lee over 11 years
    animate({height: 'auto'}) doesn't have any effect. At least, not with jQuery 1.6.4.
  • user56reinstatemonica8
    user56reinstatemonica8 over 11 years
    It should be mentioned that this requires the Jquery UI plugin, while the original question was about jquery alone. But if you're using Jquery UI, it works.
  • rg89
    rg89 over 11 years
    This works, but I added a callback that restores the auto-grow behavior to the element .animated({height: autoHeight}, 1000, function(){ el.height('auto'); });
  • Jaap
    Jaap over 11 years
    This doesn't solve the height:auto function since slideUp will completely collapse the div.
  • Jaap
    Jaap over 11 years
    This oneliner is not easy to understand, maybe writing several lines would help others a little better.
  • Antoine Hedgecock
    Antoine Hedgecock over 10 years
    you could also use $(this).toggleClass('max', 250); instead of using the if statement
  • Jonathan Tonge
    Jonathan Tonge over 10 years
    Becareful about setting fixed heights on responsive designs. It turns into a mess if the user resizes the screen. Best to set height to 'auto' once the animation is complete.
  • Ricky Sahu
    Ricky Sahu almost 10 years
    This is the best solution because the auto height may change if the user adjusts the window size. See the following: //animates the height of the filters function toggleSlider(){ if ($('#filters').height() != 0) { $('#filters').animate({height:'0'}); } else{ var $selector = $('#filters'); $selector .data('oHeight',$selector.height()) .css('height','auto') .data('nHeight',$selector.height()) .height($selector.data('oHeight')) .animate({height: $selector.data('nHeight')},400); }; console.log('agg'); }
  • Steffi
    Steffi almost 10 years
    you can replace : .appendTo("body") by .appendTo(el.parent())
  • PHearst
    PHearst over 9 years
    If you don't start with a fixed height of '200px' like the OP, you can set the element to '100%' with CSS and it works as well.
  • Dingredient
    Dingredient over 9 years
    This has the potential to cause FOUC. The user might see the element jump to full height for a split second before animating.
  • Sven
    Sven over 9 years
    Amazing! According to developer.mozilla.org/en-US/docs/Web/API/Element.scrollHeigh‌​t it's even supported in IE8, compared to clientHeight, which seems to be unsupported: developer.mozilla.org/en-US/docs/Web/API/Element.clientHeigh‌​t
  • Timothy Groote
    Timothy Groote about 9 years
    Essentially the same as Hettler's one liner, but easier to understand.
  • Jack James
    Jack James about 9 years
    this doesn't seem to take margins into account
  • Liquinaut
    Liquinaut almost 9 years
    Margin is by definition of the box model not part of the height of an object. You could always add the margin yourself, though.
  • bytesized
    bytesized almost 9 years
    I was having problems with the accepted answer. Sometimes (but not always), it would get the same value for the current height and the auto height. This answer works perfectly for me. I am surprised I have never seen the scrollHeight property before.
  • Einius
    Einius almost 9 years
    This should be the accepted answer as it works best without any flickering and really does the job well
  • FiftyStars
    FiftyStars over 8 years
    temporary switching to auto height is really visible for a couple of frames
  • Chris Williams
    Chris Williams over 8 years
    I also think this is the best solution. I would add to it a callback function to set height to auto for more responsiveness. $('#first').animate({ height: $('#first').get(0).scrollHeight }, 1000, function() { $(this).height('auto'); });
  • nils
    nils over 8 years
    Wow, this is super elegant. It also works with scrollWidth for width animations.
  • tomarrell
    tomarrell over 8 years
    Fantastic solution. Deserves the accept. Also works when the window is resized whereas the other doesn't unless you write a function to modify the initial heights and redo all the calculations.
  • ntgCleaner
    ntgCleaner about 8 years
    Works to make the div open up, but does not animate over 400ms. Maybe I have something else set differently, but it just opens in a blink.
  • JacobEvelyn
    JacobEvelyn about 8 years
    You can prevent the FOUC ("flash of unstyled content") by initially giving the element opacity: 0; position: absolute; while measuring it and removing those once you're done.
  • Stan George
    Stan George almost 8 years
    If you don't want to use that function just do something like: var clone = element.clone() clone.appendTo('body') clone.css('height', 'auto') var itemHeight = clone.outerHeight(); clone.remove() now you have your item's height in itemHeight variable, so you can use it for more than just animations.
  • jsruok
    jsruok almost 7 years
    Works but this sets height to a fixed value (e.g. 122px). My element changed height after a while, so I had to replace the duration argument (400) with options {duration: 400, complete: function() {$selector.css('height', 'auto');}}
  • bowl0stu
    bowl0stu almost 7 years
    why are you including a second value with the .addClass and .removeClass ?