[javascript] Animate element to auto height with jQuery

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

This question is related to javascript jquery html css jquery-animate

The answer is


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


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


You can make Liquinaut's answer responsive to window size changes by adding a callback that sets the height back to auto.

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

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

you can always do this:

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

here is a fiddle: http://jsfiddle.net/Zuriel/faE9w/2/


Your selectors don't seem to match. Does your element have an ID of 'first', or is it the first element in every div?

A safer solution would be to use 'this':

// assuming the div you want to animate has an ID of first
$('#first').click(function() {
  $(this).animate({ height : 'auto' }, 1000);
});

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


You can always wrap the child elements of #first and save height height of the wrapper as a variable. This might not be the prettiest or most efficient answer, but it does the trick.

Here's a fiddle where I included a reset.

but for your purposes, here's the meat & potatoes:

$(function(){
//wrap everything inside #first
$('#first').children().wrapAll('<div class="wrapper"></div>');
//get the height of the wrapper 
var expandedHeight = $('.wrapper').height();
//get the height of first (set to 200px however you choose)
var collapsedHeight = $('#first').height();
//when you click the element of your choice (a button in my case) #first will animate to height auto
$('button').click(function(){
    $("#first").animate({
        height: expandedHeight            
    })
});
});?

I am posting this answer even though this thread is old. I couldn't get the accepted answer to work for me. This one works well and is pretty simple.

I load the height of each div I want into the data

$('div').each(function(){
    $(this).data('height',$(this).css('height'));
    $(this).css('height','20px');
});

Then I just use that when animating on click.

$('div').click(function(){
    $(this).css('height',$(this).data('height'));
});

I am using CSS transition, so I don't use the jQuery animate, but you could do animate just the same.


I managed to fix it :D heres the code.

var divh = document.getElementById('first').offsetHeight;
$("#first").css('height', '100px');
$("div:first").click(function() {
  $("#first").animate({
    height: divh
  }, 1000);
});

Toggle slide (Box9's answer expanded)

_x000D_
_x000D_
$("#click-me").click(function() {_x000D_
  var el = $('#first'),_x000D_
  curHeight = el.height(),_x000D_
  autoHeight = el.css('height', 'auto').height(),_x000D_
  finHeight = $('#first').data('click') == 1 ? "20px" : autoHeight;_x000D_
  $('#first').data('click', $(this).data('click') == 1 ? false : true);_x000D_
  el.height(curHeight).animate({height: finHeight});_x000D_
});
_x000D_
#first {width: 100%;height: 20px;overflow:hidden;}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<div id="first">_x000D_
  <div id="click-me">Lorem ipsum dolor sit amet, consectetur adipiscing elit</div>_x000D_
  Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,_x000D_
</div>
_x000D_
_x000D_
_x000D_


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

I put together something that does exactly what I was looking for and looks great. Using the scrollHeight of an element gets you the height of when it was loaded in the DOM.

_x000D_
_x000D_
 var clickers = document.querySelectorAll('.clicker');_x000D_
    clickers.forEach(clicker => {_x000D_
        clicker.addEventListener('click', function (e) {_x000D_
            var node = e.target.parentNode.childNodes[5];_x000D_
            if (node.style.height == "0px" || node.style.height == "") {_x000D_
                $(node).animate({ height: node.scrollHeight });_x000D_
            }_x000D_
            else {_x000D_
                $(node).animate({ height: 0 });_x000D_
            }_x000D_
        });_x000D_
    });
_x000D_
.answer{_x000D_
        font-size:15px;_x000D_
        color:blue;_x000D_
        height:0px;_x000D_
        overflow:hidden;_x000D_
       _x000D_
    }
_x000D_
 <div class="row" style="padding-top:20px;">_x000D_
                <div class="row" style="border-color:black;border-style:solid;border-radius:4px;border-width:4px;">_x000D_
                    <h1>This is an animation tester?</h1>_x000D_
                    <span class="clicker">click me</span>_x000D_
                    <p class="answer">_x000D_
                        I will be using this to display FAQ's on a website and figure you would like this.  The javascript will allow this to work on all of the FAQ divs made by my razor code.  the Scrollheight is the height of the answer element on the DOM load.  Happy Coding :)_x000D_
                         Lorem ipsum dolor sit amet, mea an quis vidit autem. No mea vide inani efficiantur, mollis admodum accusata id has, eam dolore nemore eu. Mutat partiendo ea usu, pri duis vulputate eu. Vis mazim noluisse oportere id. Cum porro labore in, est accumsan euripidis scripserit ei. Albucius scaevola elaboraret usu eu. Ad sed vivendo persecuti, harum movet instructior eam ei._x000D_
                    </p>_x000D_
                </div>_x000D_
            </div>_x000D_
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
_x000D_
_x000D_
_x000D_


Basically the height auto is only available for you after the element is rendered. If you set a fixed height, or if your element is not displayed you can't access it without any tricks.

Luckily there are some tricks you may use.

Clone the element, display it outside of the view give it height auto and you can take it from the clone and use it later for the main element. I use this function and seems to work well.

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

Use slideDown and slideUp

$("div:first").click(function(){ $("#first").slideDown(1000); });

you can store it in a data attribute.

$('.colapsable').each(function(){
    $(this).attr('data-oheight',$(this).height());
    $(this).height(100);
});

$('.colapsable h2:first-child').click(function(){
    $(this).parent('.colapsable').animate({
            height: $(this).parent('.colapsible').data('oheight')
        },500);
    }
});

If all you are wanting is to show and hide say a div, then this code will let you use jQuery animate. You can have jQuery animate the majority of the height you wish or you can trick animate by animating to 0px. jQuery just needs a height set by jQuery to convert it to auto. So the .animate adds the style="" to the element that .css(height:auto) converts.

The cleanest way I have seen this work is to animate to around the height you expect, then let it set auto and it can look very seamless when done right. You can even animate past what you expect and it will snap back. Animating to 0px at a duration of 0 just simply drops the element height to its auto height. To the human eye, it looks animated anyway. Enjoy..

    jQuery("div").animate({
         height: "0px"/*or height of your choice*/
    }, {
         duration: 0,/*or speed of your choice*/
         queue: false, 
         specialEasing: {
             height: "easeInCirc"
        },
         complete: function() {
             jQuery(this).css({height:"auto"});
        }
    });

Sorry I know this is an old post, but I felt this would be relevant to users seeking this functionality still with jQuery who come across this post.


var h = document.getElementById('First').scrollHeight;
$('#First').animate({ height : h+'px' },300);

I needed this functionality for multiple read more area's on one page implementing this into a Wordpress shortcode I ran into the same problem.

Design technically all of the read more span's on the page have a fixed height. And I wanted to be able to expand them separately to an auto height with a toggle. First click: 'expand to full height of text span', second click: 'collapse back to default height of 70px'

Html

 <span class="read-more" data-base="70" data-height="null">
     /* Lots of text determining the height of this span */
 </span>
 <button data-target='read-more'>Read more</button>

CSS

span.read-more {
    position:relative;
    display:block;
    overflow:hidden;
}

So above this looks very simple the data-base attribute I need to set the fixed height needed. The data-height attribute I used to store the actual (dynamic) height of the element.

The jQuery part

jQuery(document).ready(function($){

  $.fn.clickToggle = function(func1, func2) {
      var funcs = [func1, func2];
      this.data('toggleclicked', 0);
      this.click(function() {
          var data = $(this).data();
          var tc = data.toggleclicked;
          $.proxy(funcs[tc], this)();
          data.toggleclicked = (tc + 1) % 2;
      });
      return this;
  };

    function setAttr_height(key) {
        $(key).each(function(){
            var setNormalHeight = $(this).height();
            $(this).attr('data-height', setNormalHeight);
            $(this).css('height', $(this).attr('data-base') + 'px' );
        });
    }
    setAttr_height('.read-more');

    $('[data-target]').clickToggle(function(){
        $(this).prev().animate({height: $(this).prev().attr('data-height')}, 200);
    }, function(){
        $(this).prev().animate({height: $(this).prev().attr('data-base')}, 200);
    });

});

First I've used a clickToggle function for my first and second click. The second function is more important: setAttr_height() All of the .read-more elements have their actual heights set on page load in the base-height attribute. After that the base height is set through the jquery css function.

With both of our attributes set we now can toggle between them in a smooth way. Only chang the data-base to your desired (fixed)height and switch the .read-more class for your own ID

You can all see it working in a fiddle FIDDLE

No jQuery UI needed


Try this one ,

var height;
$(document).ready(function(){
    $('#first').css('height','auto');
    height = $('#first').height();
    $('#first').css('height','200px');
})

 $("div:first").click(function(){
  $("#first").animate({
    height: height
  }, 1000 );
});

Here's one that works with BORDER-BOX ...

Hi guys. Here is a jQuery plugin I wrote to do the same, but also account for the height differences that will occur when you have box-sizing set to border-box.

I also included a "yShrinkOut" plugin that hides the element by shrinking it along the y-axis.


// -------------------------------------------------------------------
// Function to show an object by allowing it to grow to the given height value.
// -------------------------------------------------------------------
$.fn.yGrowIn = function (growTo, duration, whenComplete) {

    var f = whenComplete || function () { }, // default function is empty
        obj = this,
        h = growTo || 'calc', // default is to calculate height
        bbox = (obj.css('box-sizing') == 'border-box'), // check box-sizing
        d = duration || 200; // default duration is 200 ms

    obj.css('height', '0px').removeClass('hidden invisible');
    var padTop = 0 + parseInt(getComputedStyle(obj[0], null).paddingTop), // get the starting padding-top
        padBottom = 0 + parseInt(getComputedStyle(obj[0], null).paddingBottom), // get the starting padding-bottom
        padLeft = 0 + parseInt(getComputedStyle(obj[0], null).paddingLeft), // get the starting padding-left
        padRight = 0 + parseInt(getComputedStyle(obj[0], null).paddingRight); // get the starting padding-right
    obj.css('padding-top', '0px').css('padding-bottom', '0px'); // Set the padding to 0;

    // If no height was given, then calculate what the height should be.
    if(h=='calc'){ 
        var p = obj.css('position'); // get the starting object "position" style. 
        obj.css('opacity', '0'); // Set the opacity to 0 so the next actions aren't seen.
        var cssW = obj.css('width') || 'auto'; // get the CSS width if it exists.
        var w = parseInt(getComputedStyle(obj[0], null).width || 0) // calculate the computed inner-width with regard to box-sizing.
            + (!bbox ? parseInt((getComputedStyle(obj[0], null).borderRightWidth || 0)) : 0) // remove these values if using border-box.
            + (!bbox ? parseInt((getComputedStyle(obj[0], null).borderLeftWidth || 0)) : 0) // remove these values if using border-box.
            + (!bbox ? (padLeft + padRight) : 0); // remove these values if using border-box.
        obj.css('position', 'fixed'); // remove the object from the flow of the document.
        obj.css('width', w); // make sure the width remains the same. This prevents content from throwing off the height.
        obj.css('height', 'auto'); // set the height to auto for calculation.
        h = parseInt(0); // calculate the auto-height
        h += obj[0].clientHeight // calculate the computed height with regard to box-sizing.
            + (bbox ? parseInt((getComputedStyle(obj[0], null).borderTopWidth || 0)) : 0) // add these values if using border-box.
            + (bbox ? parseInt((getComputedStyle(obj[0], null).borderBottomWidth || 0)) : 0) // add these values if using border-box.
            + (bbox ? (padTop + padBottom) : 0); // add these values if using border-box.
        obj.css('height', '0px').css('position', p).css('opacity','1'); // reset the height, position, and opacity.
    };

    // animate the box. 
    //  Note: the actual duration of the animation will change depending on the box-sizing.
    //      e.g., the duration will be shorter when using padding and borders in box-sizing because
    //      the animation thread is growing (or shrinking) all three components simultaneously.
    //      This can be avoided by retrieving the calculated "duration per pixel" based on the box-sizing type,
    //      but it really isn't worth the effort.
    obj.animate({ 'height': h, 'padding-top': padTop, 'padding-bottom': padBottom }, d, 'linear', (f)());
};

// -------------------------------------------------------------------
// Function to hide an object by shrinking its height to zero.
// -------------------------------------------------------------------
$.fn.yShrinkOut = function (d,whenComplete) {
    var f = whenComplete || function () { },
        obj = this,
        padTop = 0 + parseInt(getComputedStyle(obj[0], null).paddingTop),
        padBottom = 0 + parseInt(getComputedStyle(obj[0], null).paddingBottom),
        begHeight = 0 + parseInt(obj.css('height'));

    obj.animate({ 'height': '0px', 'padding-top': 0, 'padding-bottom': 0 }, d, 'linear', function () {
            obj.addClass('hidden')
                .css('height', 0)
                .css('padding-top', padTop)
                .css('padding-bottom', padBottom);
            (f)();
        });
};

Any of the parameters I used can be omitted or set to null in order to accept default values. The parameters I used:

  • growTo: If you want to override all the calculations and set the CSS height to which the object will grow, use this parameter.
  • duration: The duration of the animation (obviously).
  • whenComplete: A function to run when the animation is complete.

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to jquery-animate

jQuery .scrollTop(); + animation CSS rotation cross browser with jquery.animate() jquery toggle slide from left to right and back How to animate CSS Translate jQuery animate margin top animating addClass/removeClass with jQuery Animate scroll to ID on page load Change text (html) with .animate jquery animate background position Animate element to auto height with jQuery