【问题标题】:Animate element to auto height with jQuery使用 jQuery 将元素设置为自动高度
【发布时间】:2011-06-27 13:20:30
【问题描述】:

我想将<div>200px 动画到auto 高度。不过,我似乎无法让它发挥作用。有人知道怎么做吗?

代码如下:

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

【问题讨论】:

标签: javascript jquery html css jquery-animate


【解决方案1】:
  1. 保存当前高度:

    var curHeight = $('#first').height();
    
  2. 暂时将高度切换为自动:

    $('#first').css('height', 'auto');
    
  3. 获取自动高度:

    var autoHeight = $('#first').height();
    
  4. 切换回curHeight 并动画到autoHeight

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

一起:

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

【讨论】:

  • @Daniel,你的 JS 代码在哪里?发布该位,以及显示您引用的元素的 HTML 部分。
  • 这行得通,但我添加了一个回调,将自动增长行为恢复到元素 .animated({height: autoHeight}, 1000, function(){ el.height('auto'); });
  • 在响应式设计上设置固定高度时要小心。如果用户调整屏幕大小,它就会变得一团糟。动画完成后最好将高度设置为“自动”。
  • 这有可能导致 FOUC。用户可能会在制作动画前的一瞬间看到元素跳到全高。
  • 你可以防止 FOUC(“无样式内容的闪现”),方法是在测量元素时首先给出元素 opacity: 0; position: absolute;,然后在完成后将其删除。
【解决方案2】:

IMO 这是最干净、最简单的解决方案:

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

解释:DOM 已经从它的初始渲染中知道当设置为自动高度时展开的 div 的大小。该属性以scrollHeight 的形式存储在DOM 节点中。我们只需要通过调用get(0) 来从jQuery 元素中获取DOM 元素,然后我们就可以访问该属性了。

添加回调函数以将高度设置为 auto 可以在动画完成后提高响应速度(信用 chris-williams):

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

【讨论】:

  • 太棒了!根据developer.mozilla.org/en-US/docs/Web/API/Element.scrollHeight 的说法,它甚至在IE8 中得到支持,而clientHeight 似乎不受支持:developer.mozilla.org/en-US/docs/Web/API/Element.clientHeight
  • 边距是盒子模型的定义,不是物体高度的一部分。不过,您总是可以自己添加边距。
  • 这应该是公认的答案,因为它在没有任何闪烁的情况下效果最好,并且确实做得很好
  • 我也认为这是最好的解决方案。我会添加一个回调函数来将高度设置为自动以获得更多响应。 $('#first').animate({ height: $('#first').get(0).scrollHeight }, 1000, function() { $(this).height('auto'); });
  • 哇,这太优雅了。它也适用于 scrollWidth 的宽度动画。
【解决方案3】:

这与 Box9 的答案基本相同,但我将它包装在一个不错的 jquery 插件 中,该插件采用与常规动画相同的参数,当你需要更多的动画参数并且厌倦了一遍又一遍地重复相同的代码:

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

编辑:现在可链接且更干净

【讨论】:

    【解决方案4】:

    更好的解决方案是不依赖 JS 来设置元素的高度。以下是将固定高度元素设置为完整(“自动”)高度的解决方案:

    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

    【讨论】:

    • 这个oneliner不好理解,写几行可能对别人有帮助。
    • 这是最好的解决方案,因为如果用户调整窗口大小,自动高度可能会改变。请参阅以下内容: //动画过滤器的高度 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'); }
    • 可以使 div 打开,但动画不会超过 400 毫秒。也许我有其他设置不同,但它只是一眨眼就打开了。
    • 有效,但这会将height 设置为固定值(例如122px)。一段时间后我的元素改变了高度,所以我不得不用选项替换持续时间参数(400){duration: 400, complete: function() {$selector.css('height', 'auto');}}
    【解决方案5】:

    这是有效的,它比以前的解决方案更简单:

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

    注意:此解决方案需要 jQuery UI

    【讨论】:

    • 需要说明的是,这需要Jquery UI插件,而最初的问题是关于jquery的。但如果你使用的是 Jquery UI,它就可以工作。
    • 你也可以使用 $(this).toggleClass('max', 250);而不是使用 if 语句
    • 为什么要在 .addClass.removeClass 中包含第二个值?
    【解决方案6】:
    var h = document.getElementById('First').scrollHeight;
    $('#First').animate({ height : h+'px' },300);
    

    【讨论】:

      【解决方案7】:

      您始终可以包装#first 的子元素并将包装器的高度高度保存为变量。这可能不是最漂亮或最有效的答案,但它可以解决问题。

      这是一个fiddle,我在其中包含了一个重置​​。

      但为了您的目的,这里是肉和土豆:

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

      【讨论】:

        【解决方案8】:

        使用slideDownslideUp

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

        【讨论】:

        • 这并不能解决 height:auto 函数,因为 slideUp 会完全折叠 div。
        【解决方案9】:

        我设法修复了它:D 这是代码。

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

        【讨论】:

          【解决方案10】:

          您可以通过添加将高度设置回自动的回调来使 Liquinaut 的答案响应窗口大小的变化。

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

          【讨论】:

            【解决方案11】:

            基本上,高度自动仅在元素渲染后才对您可用。 如果你设置了一个固定的高度,或者你的元素没有显示出来,你就无法在没有任何技巧的情况下访问它。

            幸运的是,您可以使用一些技巧。

            克隆元素,将其显示在视图之外,给它自动高度,您可以从克隆中获取它,稍后将其用于主元素。 我用了这个功能,感觉效果不错。

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

            用法:

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

            【讨论】:

            • 如果您不想使用该功能,只需执行以下操作: var clone = element.clone() clone.appendTo('body') clone.css('height', 'auto' ) var itemHeight = clone.outerHeight(); clone.remove() 现在你在 itemHeight 变量中有你的项目的高度,所以你可以将它用于不仅仅是动画。
            【解决方案12】:

            您的选择器似乎不匹配。您的元素的 ID 是否为“first”,还是每个 div 中的第一个元素?

            更安全的解决方案是使用“this”:

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

            【讨论】:

            • 啊。好吧,看来您已经找到了解决方案。为了安全起见,我仍然会在您的点击处理程序中使用$(this)
            • animate({height: 'auto'}) 没有任何效果。至少,不是 jQuery 1.6.4。
            【解决方案13】:

            你总是可以这样做:

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

            这是一个小提琴: http://jsfiddle.net/Zuriel/faE9w/2/

            【讨论】:

            • 你可以用.appendTo(el.parent())替换:.appendTo("body")
            【解决方案14】:

            试试这个,

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

            【讨论】:

            • 这是行不通的,你的 var 高度只能在 ready 函数中访问。
            • 在ready函数之前定义高度,并且只使用高度而不是var height..这样它可能会起作用daniel
            【解决方案15】:

            这是一个适用于 BORDER-BOX ...

            大家好。这是我写的一个 jQuery 插件来做同样的事情,但也考虑了当你将box-sizing 设置为border-box 时会出现的高度差异。

            我还包括一个“yShrinkOut”插件,它通过沿 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)();
                    });
            };
            

            我使用的任何参数都可以省略或设置为 null 以接受默认值。我使用的参数:

            • growTo:如果要覆盖所有计算并设置对象将增长到的 CSS 高度,请使用此参数。
            • 持续时间:动画的持续时间(显然)。
            • whenComplete:动画完成时运行的函数。

            【讨论】:

              【解决方案16】:

              切换幻灯片(Box9's answer 展开)

              $("#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>

              【讨论】:

                【解决方案17】:

                如果您只想显示和隐藏一个 div,那么这段代码将让您使用 jQuery animate。您可以让 jQuery 为您希望的大部分高度设置动画,或者您可以通过将动画设置为 0px 来欺骗动画。 jQuery 只需要 jQuery 设置的高度即可将其转换为自动。因此 .animate 将 style="" 添加到 .css(height:auto) 转换的元素中。

                我见过的最简洁的方法是动画到你期望的高度,然后让它设置为自动,如果做得好,它看起来非常无缝。您甚至可以制作超出预期的动画,它会迅速恢复。以 0 的持续时间动画到 0px 只是简单地将元素高度降低到其自动高度。对人眼来说,它看起来无论如何都是动画的。享受..

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

                抱歉,我知道这是一篇旧帖子,但我觉得这与仍然使用 jQuery 的用户在遇到此帖子时寻求此功能有关。

                【讨论】:

                  【解决方案18】:

                  即使这个帖子很旧,我也会发布这个答案。我无法得到为我工作的公认答案。这个效果很好,而且非常简单。

                  我将我想要的每个 div 的高度加载到数据中

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

                  然后我只是在点击动画时使用它。

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

                  我使用的是 CSS 过渡,所以我不使用 jQuery 动画,但你可以做同样的动画。

                  【讨论】:

                    【解决方案19】:

                    您可以将其存储在数据属性中。

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

                    【讨论】:

                    • 与 Hettler 的 one liner 基本相同,但更容易理解。
                    【解决方案20】:

                    我需要这个功能来实现一个页面上的多个阅读更多区域,将它实现到一个 Wordpress 短代码中,我遇到了同样的问题。

                    从技术上讲,页面上的所有阅读更多跨度都有固定的高度。我希望能够通过切换将它们分别扩展到自动高度。第一次点击:“展开到文本跨度的全高”,第二次点击:“折叠回默认高度 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;
                    }
                    

                    所以上面这个看起来很简单data-base 属性我需要设置所需的固定高度。我用来存储元素实际(动态)高度的data-height 属性。

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

                    首先,我在第一次和第二次点击中使用了 clickToggle 函数。第二个功能更重要:setAttr_height() 所有.read-more 元素在base-height 属性中设置页面加载时的实际高度。之后,通过 jquery css 函数设置基本高度。

                    通过设置我们的两个属性,我们现在可以流畅地在它们之间切换。只需将 data-base 更改为您想要的(固定)高度,然后将 .read-more 类切换为您自己的 ID

                    你们都可以看到它在小提琴FIDDLE

                    不需要 jQuery UI

                    【讨论】:

                      【解决方案21】:

                      我整理了一些东西,它完全符合我的要求并且看起来很棒。使用元素的 scrollHeight 可以获得它在 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>

                      【讨论】:

                        猜你喜欢
                        • 2013-09-06
                        • 1970-01-01
                        • 2012-02-28
                        • 2017-03-23
                        • 2011-05-12
                        • 1970-01-01
                        • 2011-08-05
                        • 2012-06-06
                        • 2012-03-05
                        相关资源
                        最近更新 更多