Анимировать элемент для автоматической высоты с помощью jQuery


171

Я хочу , чтобы анимировать <div>от 200pxдо autoвысоты. Я не могу заставить его работать, хотя. Кто-нибудь знает как?

Вот код:

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

14
Вы должны пометить лучший ответ как принятый.
kleinfreund


@IanMackinnon этот вопрос, безусловно, имеет лучшие ответы. Я закрыл этот вопрос как дубликат этого.
Призрак Мадары

Ответы:


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

@ Даниил, где твой код JS? Отправьте этот бит, а также части HTML, которые показывают элементы, на которые вы ссылаетесь.
Дэвид Тан

21
Это работает, но я добавил функцию обратного вызова, которая восстанавливает поведение авто-роста для элемента .animated({height: autoHeight}, 1000, function(){ el.height('auto'); });
rg89

Будьте внимательны при настройке фиксированной высоты для адаптивных дизайнов. Это превращается в беспорядок, если пользователь изменяет размер экрана. Лучше всего установить высоту на «авто» после завершения анимации.
Джонатан Тонге

4
Это может вызвать FOUC. Пользователь может увидеть, как элемент прыгнул на полную высоту за доли секунды до анимации.
Dingredient

1
Вы можете предотвратить FOUC («флэш-содержимое без стилей»), первоначально предоставив элемент opacity: 0; position: absolute;при его измерении и удалив его, как только вы закончите.
Джейкоб Эвелин

194

ИМО это самое чистое и простое решение:

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

Объяснение: DOM уже знает из своего начального рендеринга, какой размер будет иметь расширенный div, если он установлен на автоматическую высоту. Это свойство хранится в узле DOM как scrollHeight. Нам просто нужно извлечь элемент DOM из элемента jQuery, вызвав его, get(0)и тогда мы сможем получить доступ к свойству.

Добавление функции обратного вызова для установки высоты в автоматический режим позволяет повысить скорость отклика после завершения анимации (кредит chris-williams ):

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

2
Удивительный! Согласно developer.mozilla.org/en-US/docs/Web/API/Element.scrollHeight, он даже поддерживается в IE8, по сравнению с clientHeight, который, кажется, не поддерживается: developer.mozilla.org/en-US/docs/Web/ API / Element.clientHeight
Свен,

1
Поля по определению блочной модели не являются частью высоты объекта. Вы всегда можете добавить запас самостоятельно.
Liquinaut

22
Это должен быть принятый ответ, так как он работает лучше всего без каких-либо мерцаний и действительно хорошо
справляется

7
Я также думаю, что это лучшее решение. Я бы добавил к нему функцию обратного вызова, чтобы установить высоту на авто для большей отзывчивости. $('#first').animate({ height: $('#first').get(0).scrollHeight }, 1000, function() { $(this).height('auto'); });
Крис Уильямс

1
Вау, это супер элегантно Это также работает scrollWidthдля анимации ширины.
ноль

24

По сути, это тот же подход, что и в ответе 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);

редактировать: цепной и чище сейчас


23

Лучшее решение не будет полагаться на 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


2
Это не легко понять, возможно, написание нескольких строк поможет другим немного лучше.
Яап

Это лучшее решение, потому что автоматическая высота может измениться, если пользователь регулирует размер окна. Смотрите следующее: // анимирует высоту функции filter 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 мс. Может быть, у меня есть что-то другое, но оно открывается в одно мгновение.
ntgCleaner

Работает, но при этом устанавливается heightфиксированное значение (например, 122px). Мой элемент через некоторое время изменил высоту, поэтому мне пришлось заменить аргумент продолжительности (400) на опции{duration: 400, complete: function() {$selector.css('height', 'auto');}}
jsruok

12

это работает, и это проще, чем решения раньше:

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.


1
Следует отметить, что для этого требуется плагин пользовательского интерфейса Jquery, тогда как первоначальный вопрос касался только jquery. Но если вы используете Jquery UI, это работает.
user56reinstatemonica8

4
Вы также можете использовать $ (this) .toggleClass ('max', 250); вместо использования оператора if
Антуан Хеджекок

1
почему вы включаете второе значение в .addClassи .removeClass?
bow0stu


7

Вы всегда можете обернуть дочерние элементы #first и сохранить высоту высоты оболочки как переменную. Это может быть не самый красивый и эффективный ответ, но он делает свое дело.

Вот скрипка, где я включил сброс.

но для ваших целей вот мясо и картофель:

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


5

Мне удалось это исправить: D вот код.

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

4

Вы можете сделать ответ Liquinaut реагирующим на изменения размера окна, добавив обратный вызов, который возвращает высоту автоматически.

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

4

По сути, высота auto доступна только после визуализации элемента. Если вы установили фиксированную высоту или если ваш элемент не отображается, вы не сможете получить к нему доступ без каких-либо хитростей.

К счастью, есть некоторые приемы, которые вы можете использовать.

Клонируйте элемент, отобразите его за пределами представления и задайте ему высоту автоматически, и вы можете взять его из клона и использовать его позже для основного элемента. Я использую эту функцию и, кажется, работает хорошо.

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

1
Если вы не хотите использовать эту функцию, просто сделайте что-то вроде: var clone = element.clone () clone.appendTo ('body') clone.css ('height', 'auto') var itemHeight = clone.outerHeight ( ); clone.remove () теперь у вас есть высота вашего элемента в переменной itemHeight, так что вы можете использовать ее не только для анимации.
Стэн Джордж

3

Вы всегда можете сделать это:

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/


1
Вы можете заменить: .appendTo("body")на.appendTo(el.parent())
Штеффи

2

Ваши селекторы не совпадают. У вашего элемента есть идентификатор 'first', или это первый элемент в каждом div?

Более безопасным решением было бы использовать «это»:

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

1
Ах. Ну, похоже, вы нашли решение. В целях безопасности я все еще использовал бы $(this)внутри вашего обработчика кликов.
ЭММЕРИХ

10
animate({height: 'auto'})не имеет никакого эффекта. По крайней мере, не с JQuery 1.6.4.
Янис Элмерис

2

Попробуй это ,

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

это не сработает, ваша высота переменной просто доступна внутри функции ready.
Мео

определите высоту перед функцией готовности и используйте только высоту, а не высоту. Таким образом, это может сработать Даниэль
Пракаш

2

Вот тот, который работает с 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)();
        });
};

Любой из параметров, которые я использовал, может быть опущен или установлен в нуль для принятия значений по умолчанию. Параметры, которые я использовал:

  • growTo: если вы хотите переопределить все вычисления и установить высоту CSS, до которой будет расти объект, используйте этот параметр.
  • длительность: продолжительность анимации ( очевидно ).
  • whenComplete: функция, запускаемая после завершения анимации.

2

Переключить слайд ( ответ Box9 расширен)

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


1

Я публикую этот ответ, хотя эта ветка старая. Я не мог получить принятый ответ, чтобы работать на меня. Этот работает хорошо и довольно просто.

Я загружаю высоту каждого деления в данные

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

Тогда я просто использую это при анимации по клику.

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

Я использую переход CSS, поэтому я не использую анимацию jQuery, но вы можете сделать анимацию точно так же.


1

Вы можете сохранить его в атрибуте данных.

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

По сути, такой же, как один лайнер Хеттлера, но проще для понимания.
Тимоти Грут

1

Мне нужна была эта функциональность для нескольких областей read more на одной странице, которые реализовали это в шорткоде Wordpress. Я столкнулся с той же проблемой.

Технически, все разделы read more на странице имеют фиксированную высоту. И я хотел иметь возможность расширить их по отдельности до автоматической высоты с помощью переключателя. Первый щелчок: «развернуть до полной высоты текстового промежутка», второй щелчок: «свернуть до высоты по умолчанию 70 пикселей»

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 для своего собственного идентификатора.

Вы все можете увидеть это работает на скрипке FIDDLE

Не требуется JQuery UI


1

Если все, что вам нужно, это показать и скрыть, скажем, div, то этот код позволит вам использовать jQuery animate. Вы можете сделать так, чтобы jQuery анимировал большую часть желаемой высоты, или вы можете обмануть, оживив до 0px. jQuery просто нужна высота, установленная jQuery, чтобы преобразовать ее в авто. Таким образом .animate добавляет style = "" к элементу, который преобразует .css (height: auto).

Самый чистый способ, которым я видел эту работу, состоит в том, чтобы анимировать примерно на ожидаемую высоту, а затем позволить ей установить автоматический режим, и при правильной работе он может выглядеть очень плавно. Вы даже можете оживить прошлое, что вы ожидаете, и оно вернется назад. Анимация до 0px при длительности 0 просто снижает высоту элемента до его автоматической высоты. Человеческому глазу все равно это выглядит оживленно. Наслаждаться..

    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, которые сталкиваются с этим постом.


0

Я собрал что-то, что делает именно то, что я искал и выглядит великолепно. Использование 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>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.