Animar elemento a altura automática con jQuery

171

Quiero animar un <div>desde 200pxa la autoaltura. Aunque parece que no puedo hacer que funcione. ¿Alguien sabe cómo?

Aquí está el código:

$("div:first").click(function(){
  $("#first").animate({
    height: "auto"
  }, 1000 );
});
Daniel
fuente
14
Debe marcar la mejor respuesta como aceptada.
kleinfreund
@IanMackinnon esta pregunta ciertamente tiene mejores respuestas. He cerrado esa pregunta como un duplicado de esto.
El fantasma de Madara

Respuestas:

254
  1. Guardar la altura actual:

    var curHeight = $('#first').height();
  2. Cambie temporalmente la altura a auto:

    $('#first').css('height', 'auto');
  3. Obtenga la altura automática:

    var autoHeight = $('#first').height();
  4. Vuelva a curHeightanimar a autoHeight:

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

Y juntos:

var el = $('#first'),
    curHeight = el.height(),
    autoHeight = el.css('height', 'auto').height();
el.height(curHeight).animate({height: autoHeight}, 1000);
David Tang
fuente
@Daniel, ¿dónde está tu código JS? Publique ese bit, y también partes del HTML que muestran los elementos a los que se refiere.
David Tang
21
Esto funciona, pero agregué una devolución de llamada que restaura el comportamiento de crecimiento automático del elemento .animated({height: autoHeight}, 1000, function(){ el.height('auto'); });
rg89
Procuró establecer alturas fijas en diseños receptivos. Se convierte en un desastre si el usuario cambia el tamaño de la pantalla. Lo mejor es establecer la altura en 'automático' una vez que se completa la animación.
Jonathan Tonge
44
Esto tiene el potencial de causar FOUC. El usuario puede ver el elemento saltar a la altura completa durante una fracción de segundo antes de animar.
Dingredient
1
Puede evitar el FOUC ("destello de contenido sin estilo") inicialmente dando el elemento opacity: 0; position: absolute;mientras lo mide y elimina esos una vez que haya terminado.
JacobEvelyn
194

OMI, esta es la solución más limpia y fácil:

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

Explicación: El DOM ya sabe, desde su representación inicial, qué tamaño tendrá el div expandido cuando se configure en altura automática. Esta propiedad se almacena en el nodo DOM como scrollHeight. Solo tenemos que recuperar el elemento DOM del elemento jQuery llamando get(0)y luego podemos acceder a la propiedad.

Agregar una función de devolución de llamada para establecer la altura en automático permite una mayor capacidad de respuesta una vez que se completa la animación (crédito Chris-Williams ):

$('#first').animate({
    height: $('#first').get(0).scrollHeight
}, 1000, function(){
    $(this).height('auto');
});
Liquinaut
fuente
2
¡Asombroso! De acuerdo con developer.mozilla.org/en-US/docs/Web/API/Element.scrollHeight , incluso es compatible con IE8, en comparación con clientHeight, que parece no ser compatible: developer.mozilla.org/en-US/docs/Web/ API / Element.clientHeight
Sven
1
El margen es, por definición, el modelo de caja que no forma parte de la altura de un objeto. Sin embargo, siempre puede agregar el margen usted mismo.
Liquinaut
22
Esta debería ser la respuesta aceptada, ya que funciona mejor sin parpadeos y realmente funciona bien
Einius
77
También creo que esta es la mejor solución. Agregaría una función de devolución de llamada para establecer la altura en automático para una mayor capacidad de respuesta. $('#first').animate({ height: $('#first').get(0).scrollHeight }, 1000, function() { $(this).height('auto'); });
Chris Williams
1
Wow, esto es super elegante. También funciona con scrollWidthanimaciones de ancho.
nils
24

Este es básicamente el mismo enfoque que la respuesta de Box9, pero lo envolví en un buen complemento de jquery que toma los mismos argumentos que un animado regular , para cuando necesita tener más parámetros animados y cansarse de repetir el mismo código una y otra vez :

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

editar: encadenable y más limpio ahora

w0ps
fuente
23

Una mejor solución no dependería de JS para establecer la altura de su elemento. La siguiente es una solución que anima un elemento de altura fija a la altura completa ("automática"):

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

Tim Hettler
fuente
2
Esta línea no es fácil de entender, tal vez escribir varias líneas ayudaría a otras un poco mejor.
Jaap
Esta es la mejor solución porque la altura automática puede cambiar si el usuario ajusta el tamaño de la ventana. Consulte lo siguiente: // anima la altura de la función de filtros toggleSlider () {if ($ ('# filtros'). Altura ()! = 0) {$ ('# filtros'). Animado ({altura: '0 '}); } else {var $ selector = $ ('# filtros'); $ 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'); }
Ricky
Trabaja para abrir el div, pero no anima más de 400 ms. Tal vez tengo algo más configurado de manera diferente, pero se abre en un abrir y cerrar de ojos.
ntgCleaner
Funciona pero esto se establece heighten un valor fijo (por ejemplo, 122 px). Mi elemento cambió de altura después de un tiempo, así que tuve que reemplazar el argumento de duración (400) con opciones{duration: 400, complete: function() {$selector.css('height', 'auto');}}
jsruok
12

esto está funcionando y es más simple que las soluciones anteriores:

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

    })
});

Nota: esta solución requiere jQuery UI

czLukasss
fuente
1
Cabe mencionar que esto requiere el complemento Jquery UI, mientras que la pregunta original era sobre jquery solo. Pero si está utilizando Jquery UI, funciona.
user56reinstatemonica8
44
también puede usar $ (this) .toggleClass ('max', 250); en lugar de usar la declaración if
Antoine Hedgecock
1
¿por qué incluye un segundo valor con .addClassy .removeClass?
bowl0stu
9
var h = document.getElementById('First').scrollHeight;
$('#First').animate({ height : h+'px' },300);
Ignacio Martínez
fuente
7

Siempre puede ajustar los elementos secundarios de #first y guardar la altura y la altura del contenedor como una variable. Puede que esta no sea la respuesta más bonita o más eficiente, pero funciona.

Aquí hay un violín donde incluí un reinicio.

pero para sus propósitos, aquí está la carne y las papas:

$(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            
    })
});
});​
Usha
fuente
5

Use slideDown y slideUp

$("div:first").click(function(){ $("#first").slideDown(1000); });
Ronny Sherer
fuente
1
Esto no resuelve la altura: función automática ya que slideUp colapsará completamente el div.
Jaap
5

Me las arreglé para arreglarlo: D heres el código.

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

Puede hacer que la respuesta de Liquinaut responda a los cambios en el tamaño de la ventana agregando una devolución de llamada que restablezca la altura a automática.

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

Básicamente, la altura automática solo está disponible para usted después de representar el elemento. Si establece una altura fija, o si su elemento no se muestra, no puede acceder a él sin ningún truco.

Afortunadamente, hay algunos trucos que puedes usar.

Clone el elemento, muéstrelo fuera de la vista, dele altura automática y puede tomarlo del clon y usarlo más tarde para el elemento principal. Uso esta función y parece funcionar bien.

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

USO:

$(".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); 
});
Stan George
fuente
1
Si no desea utilizar esa función, simplemente haga algo como: var clone = element.clone () clone.appendTo ('body') clone.css ('height', 'auto') var itemHeight = clone.outerHeight ( ); clone.remove () ahora tiene la altura de su elemento en la variable itemHeight, por lo que puede usarlo para algo más que animaciones.
Stan George
3

siempre puedes hacer esto:

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

Aquí hay un violín: http://jsfiddle.net/Zuriel/faE9w/2/

Zuriel
fuente
1
puede reemplazar: .appendTo("body")por.appendTo(el.parent())
Steffi
2

Sus selectores no parecen coincidir. ¿Su elemento tiene una identificación de 'primero', o es el primer elemento en cada div?

Una solución más segura sería usar 'this':

// assuming the div you want to animate has an ID of first
$('#first').click(function() {
  $(this).animate({ height : 'auto' }, 1000);
});
EMMERICH
fuente
1
Ah Bueno, parece que has descubierto la solución. Por seguridad, aún lo usaría $(this)dentro de su controlador de clics.
EMMERICH
10
animate({height: 'auto'})No tiene ningún efecto. Al menos, no con jQuery 1.6.4.
Jānis Elmeris
2

Prueba este,

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 );
});
Prakash
fuente
esto no va a funcionar, su altura de var solo es accesible dentro de la función de listo.
meo
defina la altura antes de la función ready, y use solo height que var height ... de esta manera puede funcionar daniel
Prakash
2

Aquí hay uno que funciona con BORDER-BOX ...

Hola chicos. Aquí hay un complemento jQuery que escribí para hacer lo mismo, pero también explica las diferencias de altura que ocurrirán cuando lo haya box-sizingconfigurado border-box.

También incluí un complemento "yShrinkOut" que oculta el elemento reduciéndolo a lo largo del eje y.


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

Cualquiera de los parámetros que utilicé puede omitirse o establecerse en nulo para aceptar los valores predeterminados. Los parámetros que utilicé:

  • growTo: si desea anular todos los cálculos y establecer la altura CSS a la que crecerá el objeto, use este parámetro.
  • duración: la duración de la animación ( obviamente ).
  • whenComplete: una función que se ejecutará cuando se complete la animación.
Desequilibrado
fuente
2

Alternar diapositiva ( respuesta de Box9 expandida)

$("#click-me").click(function() {
  var el = $('#first'),
  curHeight = el.height(),
  autoHeight = el.css('height', 'auto').height(),
  finHeight = $('#first').data('click') == 1 ? "20px" : autoHeight;
  $('#first').data('click', $(this).data('click') == 1 ? false : true);
  el.height(curHeight).animate({height: finHeight});
});
#first {width: 100%;height: 20px;overflow:hidden;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="first">
  <div id="click-me">Lorem ipsum dolor sit amet, consectetur adipiscing elit</div>
  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,
</div>

che-azeh
fuente
1

Estoy publicando esta respuesta a pesar de que este hilo es antiguo. No pude obtener la respuesta aceptada para trabajar para mí. Este funciona bien y es bastante simple.

Cargo la altura de cada div que quiero en los datos

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

Entonces solo lo uso al animar al hacer clic.

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

Estoy usando la transición CSS, por lo que no uso el jQuery animate, pero podría animar de la misma manera.

Leeish
fuente
1

puede almacenarlo en un atributo de datos.

$('.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);
    }
});
medios definidos
fuente
Esencialmente lo mismo que el revestimiento de Hettler, pero más fácil de entender.
Timothy Groote
1

Necesitaba esta funcionalidad para múltiples áreas de lectura más en una página, implementando esto en un código abreviado de Wordpress. Me encontré con el mismo problema.

Diseñar técnicamente todos los más leídos en la página tienen una altura fija. Y quería poder expandirlos por separado a una altura automática con una palanca. Primer clic: 'expandir a la altura total del espacio de texto', segundo clic: 'contraer de nuevo a la altura predeterminada de 70 px'

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

Entonces, por encima de esto, parece muy simple el data-baseatributo que necesito para establecer la altura fija necesaria. El data-heightatributo que solía almacenar la altura real (dinámica) del elemento.

La parte jQuery

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

});

Primero he usado una función clickToggle para mi primer y segundo clic. La segunda función es más importante: setAttr_height()todos los .read-moreelementos tienen sus alturas reales establecidas en la carga de la página en el base-heightatributo. Después de eso, la altura base se establece mediante la función jquery css.

Con nuestros dos atributos establecidos, ahora podemos alternar entre ellos de una manera suave. Solo data-basecambie la altura deseada (fija) y cambie la clase .read-more por su propia ID

Todos pueden verlo trabajando en un violín FIDDLE

No se necesita jQuery UI

Pablo
fuente
1

Si todo lo que quiere es mostrar y ocultar decir un div, entonces este código le permitirá usar jQuery animate. Puede hacer que jQuery anime la mayor parte de la altura que desee o puede engañar a animar animando a 0px. jQuery solo necesita una altura establecida por jQuery para convertirlo en automático. Entonces, .animate agrega el estilo = "" al elemento que convierte .css (height: auto).

La forma más limpia en que he visto este trabajo es animar a la altura que esperas, luego dejar que se configure automáticamente y puede verse muy uniforme cuando se hace correctamente. Incluso puede animar más allá de lo que espera y se recuperará. Animar a 0px con una duración de 0 simplemente deja caer la altura del elemento a su altura automática. Para el ojo humano, se ve animado de todos modos. Disfrutar..

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

Lo siento, sé que esta es una publicación antigua, pero sentí que sería relevante para los usuarios que buscan esta funcionalidad aún con jQuery que se encuentran con esta publicación.

designdrumm
fuente
0

Reuní algo que hace exactamente lo que estaba buscando y se ve muy bien. El uso de scrollHeight de un elemento te da la altura de cuando se cargó en el DOM.

 var clickers = document.querySelectorAll('.clicker');
    clickers.forEach(clicker => {
        clicker.addEventListener('click', function (e) {
            var node = e.target.parentNode.childNodes[5];
            if (node.style.height == "0px" || node.style.height == "") {
                $(node).animate({ height: node.scrollHeight });
            }
            else {
                $(node).animate({ height: 0 });
            }
        });
    });
.answer{
        font-size:15px;
        color:blue;
        height:0px;
        overflow:hidden;
       
    }
 <div class="row" style="padding-top:20px;">
                <div class="row" style="border-color:black;border-style:solid;border-radius:4px;border-width:4px;">
                    <h1>This is an animation tester?</h1>
                    <span class="clicker">click me</span>
                    <p class="answer">
                        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 :)
                         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.
                    </p>
                </div>
            </div>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

JimmyTwoShoes
fuente