Elemento animado para altura automática com jQuery

171

Quero animar um <div>a partir 200pxde autoaltura. Eu não consigo fazê-lo funcionar embora. Alguém sabe como?

Aqui está o código:

$("div:first").click(function(){
  $("#first").animate({
    height: "auto"
  }, 1000 );
});
Daniel
fonte
14
Você deve marcar a melhor resposta como aceita.
kleinfreund
@IanMackinnon esta pergunta certamente tem melhores respostas. Fechei essa pergunta como uma duplicata disso.
Ghost de Madara

Respostas:

254
  1. Salve a altura atual:

    var curHeight = $('#first').height();
  2. Altere temporariamente a altura para automático:

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

    var autoHeight = $('#first').height();
  4. Volte para curHeighte anime para autoHeight:

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

E juntos:

var el = $('#first'),
    curHeight = el.height(),
    autoHeight = el.css('height', 'auto').height();
el.height(curHeight).animate({height: autoHeight}, 1000);
David Tang
fonte
@ Daniel, onde está o seu código JS? Poste esse bit e também partes do HTML que mostram os elementos aos quais você se refere.
David Tang
21
Isso funciona, mas eu adicionei um callback que restaura o comportamento auto-crescer ao elemento .animated({height: autoHeight}, 1000, function(){ el.height('auto'); });
rg89
Tenha cuidado ao definir alturas fixas em projetos responsivos. Ele se torna uma bagunça se o usuário redimensionar a tela. É melhor definir a altura para 'automático' quando a animação estiver concluída.
precisa saber é o seguinte
4
Isso tem potencial para causar FOUC. O usuário pode ver o elemento pular para a altura máxima por uma fração de segundo antes de animar.
Dingredient
1
Você pode impedir o FOUC ("flash de conteúdo não estilizado") dando inicialmente o elemento opacity: 0; position: absolute;enquanto o mede e removendo aqueles quando terminar.
precisa saber é o seguinte
194

Na IMO, esta é a solução mais limpa e fácil:

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

Explicação: O DOM já sabe, desde sua renderização inicial, qual o tamanho que a div expandida terá quando definida como altura automática. Esta propriedade é armazenada no nó DOM como scrollHeight. Nós apenas temos que buscar o elemento DOM do elemento jQuery chamando get(0)e então podemos acessar a propriedade

A adição de uma função de retorno de chamada para definir a altura como automática permite maior capacidade de resposta assim que a animação estiver concluída (credit chris-williams ):

$('#first').animate({
    height: $('#first').get(0).scrollHeight
}, 1000, function(){
    $(this).height('auto');
});
Liquinaut
fonte
2
Surpreendente! De acordo com developer.mozilla.org/pt-BR/docs/Web/API/Element.scrollHeight, ele é suportado no IE8, em comparação com o clientHeightque parece não ser suportado: developer.mozilla.org/en-US/docs/Web/ API / Element.clientHeight
Sven
1
Margem é por definição do modelo de caixa que não faz parte da altura de um objeto. Você sempre pode adicionar a margem você mesmo.
Liquinaut
22
Esta deve ser a resposta aceito como ele funciona melhor sem qualquer cintilação e realmente faz o trabalho bem
Einius
7
Eu também acho que essa é a melhor solução. Eu adicionaria a ela uma função de retorno de chamada para definir a altura como automática para obter mais capacidade de resposta. $('#first').animate({ height: $('#first').get(0).scrollHeight }, 1000, function() { $(this).height('auto'); });
Chris Williams
1
Uau, isso é super elegante. Também funciona com scrollWidthanimações de largura.
nils
24

Essa é basicamente a mesma abordagem que a resposta do Box9, mas eu a envolvi em um bom plugin de jquery que usa os mesmos argumentos de uma animação normal , pois quando você precisa ter mais parâmetros animados e se cansa de repetir o mesmo código repetidamente :

;(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: encadeado e limpador agora

w0ps
fonte
23

Uma solução melhor não dependeria do JS para definir a altura do seu elemento. A seguir, é apresentada uma solução que anima um elemento de altura fixa para a altura total ("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
fonte
2
Este oneliner não é fácil de entender, talvez escrever várias linhas ajude os outros um pouco melhor.
Jaap
Esta é a melhor solução, pois a altura automática pode mudar se o usuário ajustar o tamanho da janela. Veja o seguinte: // anima a altura da função de filtros toggleSlider () {if ($ ('# filtros'). Height ()! = 0) {$ ('# filtros'). Animate ({height: '0 '}); } else {var $ seletor = $ ('# 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
Funciona para abrir a div, mas não anima mais de 400ms. Talvez eu tenha outra coisa definida de forma diferente, mas ela abre em um piscar de olhos.
NtgCleaner 11/03/16
Funciona, mas isso define heightum valor fixo (por exemplo, 122px). Meu elemento mudou altura depois de um tempo, então eu tive que substituir o argumento de duração (400) com opções{duration: 400, complete: function() {$selector.css('height', 'auto');}}
jsruok
12

isso está funcionando e é mais simples que as soluções 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 solução requer jQuery UI

czLukasss
fonte
1
Deve-se mencionar que isso requer o plugin Jquery UI, enquanto a pergunta original era apenas sobre o jquery. Mas se você estiver usando o Jquery UI, ele funcionará.
usar o seguinte comando
4
você também pode usar $ (this) .toggleClass ('max', 250); em vez de usar a instrução if
Antoine Hedgecock
1
por que você está incluindo um segundo valor com o .addClasse .removeClass?
bowl0stu
9
var h = document.getElementById('First').scrollHeight;
$('#First').animate({ height : h+'px' },300);
Ignacio Martínez
fonte
7

Você sempre pode agrupar os elementos filhos de #first e salvar a altura height do wrapper como uma variável. Essa pode não ser a resposta mais bonita ou mais eficiente, mas funciona.

Aqui está um violino onde eu incluí uma redefinição.

mas para seus propósitos, aqui está a carne e as batatas:

$(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
fonte
5

Use slideDown e slideUp

$("div:first").click(function(){ $("#first").slideDown(1000); });
Ronny Sherer
fonte
1
Isso não resolve a função height: auto, pois o slideUp recolherá completamente a div.
Jaap
5

Consegui consertar: D aqui está o código.

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

Você pode fazer com que a resposta do Liquinaut responda a alterações no tamanho da janela adicionando um retorno de chamada que ajusta a altura novamente para automático.

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

Basicamente, a altura automática está disponível apenas para você depois que o elemento é renderizado. Se você definir uma altura fixa ou se seu elemento não for exibido, não será possível acessá-lo sem truques.

Felizmente, existem alguns truques que você pode usar.

Clone o elemento, exiba-o fora da visualização, dê-lhe a altura automática e você pode retirá-lo do clone e usá-lo mais tarde para o elemento principal. Eu uso essa função e parece funcionar bem.

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
fonte
1
Se você não quiser usar essa função, faça algo como: var clone = elemento.clone () clone.appendTo ('corpo') clone.css ('altura', 'automático') var itemHeight = clone.outerHeight ( ); clone.remove () agora você tem a altura do item na variável itemHeight, para que possa usá-lo para mais do que apenas animações.
Stan George
3

você sempre pode fazer isso:

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

aqui está um violino: http://jsfiddle.net/Zuriel/faE9w/2/

Zuriel
fonte
1
você pode substituir: .appendTo("body")por.appendTo(el.parent())
Steffi
2

Seus seletores parecem não corresponder. Seu elemento tem um ID de 'primeiro' ou é o primeiro elemento em cada div?

Uma solução mais segura seria usar 'this':

// assuming the div you want to animate has an ID of first
$('#first').click(function() {
  $(this).animate({ height : 'auto' }, 1000);
});
EMMERICH
fonte
1
Ah Bem, parece que você descobriu a solução. Por segurança, eu ainda usaria $(this)dentro do seu manipulador de cliques.
EMMERICH
10
animate({height: 'auto'})não tem nenhum efeito. Pelo menos, não com o jQuery 1.6.4.
Jānis Elmeris 20/08/2012
2

Tente 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
fonte
isso não vai funcionar, sua altura var está acessível dentro da função ready.
meo
definir a altura antes da função de pronto, e utilizar apenas a altura do que a altura var .. Deste modo, podem trabalhar Daniel
Prakash
2

Aqui está um que funciona com o BORDER-BOX ...

Oi pessoal. Aqui está um plugin jQuery que escrevi para fazer o mesmo, mas também leve em consideração as diferenças de altura que ocorrerão quando você box-sizingdefinirborder-box .

Também incluí um plug-in "yShrinkOut" que oculta o elemento, reduzindo-o ao longo do eixo 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)();
        });
};

Qualquer um dos parâmetros que eu usei pode ser omitido ou definido como nulo para aceitar valores padrão. Os parâmetros que eu usei:

  • growTo: se você deseja substituir todos os cálculos e definir a altura do CSS na qual o objeto crescerá, use este parâmetro.
  • duration: a duração da animação ( obviamente ).
  • whenComplete: Uma função a ser executada quando a animação estiver concluída.
Assimétrico
fonte
2

Alternar slide ( resposta do 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
fonte
1

Estou postando esta resposta mesmo que este tópico seja antigo. Não consegui que a resposta aceita funcionasse para mim. Este funciona bem e é bem simples.

Carrego a altura de cada div que eu quero nos dados

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

Então eu apenas uso isso ao animar no clique.

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

Estou usando a transição CSS, portanto, não uso o jQuery animate, mas você pode animar da mesma forma.

Leeish
fonte
1

você pode armazená-lo em um atributo de dados.

$('.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);
    }
});
mídia definida
fonte
Essencialmente o mesmo que o forro único de Hettler, mas mais fácil de entender.
Timothy Groote
1

Eu precisava dessa funcionalidade para várias áreas de mais leitura em uma página, implementando isso em um código de acesso do Wordpress. Corri para o mesmo problema.

Projete tecnicamente todas as extensões de leitura mais na página têm uma altura fixa. E eu queria poder expandi-los separadamente para uma altura automática com uma alternância. Primeiro clique: 'expandir para a altura total do espaço de texto', segundo clique: 'reduzir para a altura padrão 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;
}

Então, acima disso, parece muito simples o data-baseatributo que eu preciso para definir a altura fixa necessária. odata-height atributo que eu usei para armazenar a altura (dinâmica) real do elemento.

A parte do 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);
    });

});

Primeiro, usei a função clickToggle para o meu primeiro e segundo clique. A segunda função é mais importante: setAttr_height()todos os .read-moreelementos têm suas alturas reais definidas no carregamento da página no base-heightatributo. Depois disso, a altura da base é definida através da função jquery css.

Com os dois atributos definidos, agora podemos alternar entre eles de maneira suave. Apenas altere odata-base para sua altura desejada (fixo) e mudar a classe .read-mais para o seu próprio ID

Todos vocês podem vê-lo trabalhando em um violino FIDDLE

Não é necessária interface do usuário do jQuery

Paulo
fonte
1

Se tudo o que você deseja é mostrar e ocultar, digamos uma div, esse código permitirá que você use o jQuery animate. Você pode fazer com que o jQuery anime a maior parte da altura desejada ou você pode enganá-lo animando para 0px. O jQuery precisa apenas de uma altura definida pelo jQuery para convertê-lo em automático. Portanto, o .animate adiciona o estilo = "" ao elemento que .css (height: auto) converte.

A maneira mais limpa de ver este trabalho é animar ao redor da altura esperada e deixá-lo definir automaticamente e ele pode parecer muito perfeito quando feito da maneira certa. Você pode até animar o que você espera e ele voltará. A animação para 0px com uma duração de 0 simplesmente reduz a altura do elemento à sua altura automática. Para o olho humano, parece animado de qualquer maneira. Aproveitar..

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

Desculpe, eu sei que esta é uma postagem antiga, mas achei que isso seria relevante para os usuários que procuram essa funcionalidade ainda com o jQuery que se deparam com essa publicação.

designdrumm
fonte
0

Eu montei algo que faz exatamente o que eu estava procurando e parece ótimo. O uso do scrollHeight de um elemento fornece a altura de quando ele foi carregado no 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
fonte