Как я могу изменить высоту перехода:0;на высоту:автоматический;используете CSS?

StackOverflow https://stackoverflow.com/questions/3508605

  •  29-09-2019
  •  | 
  •  

Вопрос

Я пытаюсь создать <ul> сдвиньте вниз, используя CSS-переходы.

Тот Самый <ul> начинается с height: 0;.При наведении курсора мыши высота устанавливается равной height:auto;.Однако это приводит к тому, что он просто появляется, нет переходный период,

Если я сделаю это из height: 40px; Для height: auto;, затем он будет скользить вверх до height: 0;, а затем внезапно прыгнуть на нужную высоту.

Как еще я мог бы сделать это без использования JavaScript?

#child0 {
  height: 0;
  overflow: hidden;
  background-color: #dedede;
  -moz-transition: height 1s ease;
  -webkit-transition: height 1s ease;
  -o-transition: height 1s ease;
  transition: height 1s ease;
}
#parent0:hover #child0 {
  height: auto;
}
#child40 {
  height: 40px;
  overflow: hidden;
  background-color: #dedede;
  -moz-transition: height 1s ease;
  -webkit-transition: height 1s ease;
  -o-transition: height 1s ease;
  transition: height 1s ease;
}
#parent40:hover #child40 {
  height: auto;
}
h1 {
  font-weight: bold;
}
The only difference between the two snippets of CSS is one has height: 0, the other height: 40.
<hr>
<div id="parent0">
  <h1>Hover me (height: 0)</h1>
  <div id="child0">Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>
<hr>
<div id="parent40">
  <h1>Hover me (height: 40)</h1>
  <div id="child40">Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>

Это было полезно?

Решение

Использование max-height в преобразовании , а не height.И установите значение на max-height к чему-то большему, чем когда-либо будет в вашей коробке.

Видишь Демонстрация JSFiddle предоставлено Крисом Джорданом в другом ответ вот.

#menu #list {
    max-height: 0;
    transition: max-height 0.15s ease-out;
    overflow: hidden;
    background: #d5d5d5;
}

#menu:hover #list {
    max-height: 500px;
    transition: max-height 0.25s ease-in;
}
<div id="menu">
    <a>hover me</a>
    <ul id="list">
        <!-- Create a bunch, or not a bunch, of li's to see the timing. -->
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>

Другие советы

Вместо этого вам следует использовать scaleY.

HTML:

<p>Here (scaleY(1))</p>
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>

CSS:

ul {
    background-color: #eee;
    transform: scaleY(0);    
    transform-origin: top;
    transition: transform 0.26s ease;
}

p:hover ~ ul {
    transform: scaleY(1);
}

Я создал версию приведенного выше кода с префиксом поставщика в jsfiddle, http://jsfiddle.net/dotnetCarpenter/PhyQc/9/ и изменил ваш jsfiddle на использование scaleY вместо height, http://jsfiddle.net/dotnetCarpenter/7cnfc/206/.

В настоящее время вы не можете анимировать по высоте, если одна из задействованных высот равна auto, вы должны установить две явные высоты.

Решение, которое я всегда использовал, состояло в том, чтобы сначала исчезнуть, а затем уменьшить font-size, padding и margin ценности.Это выглядит не так же, как стирание, но работает без статического height или max-height.

Рабочий пример:

/* final display */
#menu #list {
    margin: .5em 1em;
    padding: 1em;
}

/* hide */
#menu:not(:hover) #list {
    font-size: 0;
    margin: 0;
    opacity: 0;
    padding: 0;
    /* fade out, then shrink */
    transition: opacity .25s,
                font-size .5s .25s,
                margin .5s .25s,
                padding .5s .25s;
}

/* reveal */
#menu:hover #list {
    /* unshrink, then fade in */
    transition: font-size .25s,
                margin .25s,
                padding .25s,
                opacity .5s .25s;
}
<div id="menu">
    <b>hover me</b>
    <ul id="list">
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>

<p>Another paragraph...</p>

Я знаю, что это тридцатый с чем-то ответ на этот вопрос, но я думаю, оно того стоит, так что поехали.Это настоящий Только для CSS раствор со следующими свойствами:

  • В начале нет задержки, и переход не прекращается рано.В обоих направлениях (расширение и сворачивание), если вы укажете длительность перехода 300 мс в вашем CSS, то переход займет 300 мс, точка.
  • Это изменение фактической высоты (в отличие от transform: scaleY(0)), так что это правильно, если после сворачиваемого элемента есть содержимое.
  • В то время как (как и в других решениях) там являются магические числа (например, "выберите длину, которая больше, чем когда-либо будет у вашего ящика"), это не смертельно, если ваше предположение окажется неверным.В этом случае переход может выглядеть не очень впечатляюще, но до и после перехода это не проблема:В расширенном (height: auto) состояние, все содержимое всегда имеет правильную высоту (в отличие, например, отесли вы выберете max-height это оказывается слишком низким).А в свернутом состоянии высота равна нулю, как и должно быть.

ДЕМОНСТРАЦИЯ

Вот демонстрация с тремя разборными элементами, все разной высоты, которые используют один и тот же CSS.Возможно, вы захотите нажать "полная страница" после нажатия "запустить фрагмент".Обратите внимание, что JavaScript только переключает collapsed Класс CSS, здесь нет необходимости в измерении.(Вы могли бы сделать эту точную демонстрацию вообще без какого-либо JavaScript, используя флажок или :target).Также обратите внимание, что часть CSS, отвечающая за переход, довольно короткая, а HTML требует только одного дополнительного элемента-оболочки.

$(function () {
  $(".toggler").click(function () {
    $(this).next().toggleClass("collapsed");
    $(this).toggleClass("toggled"); // this just rotates the expander arrow
  });
});
.collapsible-wrapper {
  display: flex;
  overflow: hidden;
}
.collapsible-wrapper:after {
  content: '';
  height: 50px;
  transition: height 0.3s linear, max-height 0s 0.3s linear;
  max-height: 0px;
}
.collapsible {
  transition: margin-bottom 0.3s cubic-bezier(0, 0, 0, 1);
  margin-bottom: 0;
  max-height: 1000000px;
}
.collapsible-wrapper.collapsed > .collapsible {
  margin-bottom: -2000px;
  transition: margin-bottom 0.3s cubic-bezier(1, 0, 1, 1),
              visibility 0s 0.3s, max-height 0s 0.3s;
  visibility: hidden;
  max-height: 0;
}
.collapsible-wrapper.collapsed:after
{
  height: 0;
  transition: height 0.3s linear;
  max-height: 50px;
}

/* END of the collapsible implementation; the stuff below
   is just styling for this demo */

#container {
  display: flex;
  align-items: flex-start;
  max-width: 1000px;
  margin: 0 auto;
}  


.menu {
  border: 1px solid #ccc;
  box-shadow: 0 1px 3px rgba(0,0,0,0.5);
  margin: 20px;

  
}

.menu-item {
  display: block;
  background: linear-gradient(to bottom, #fff 0%,#eee 100%);
  margin: 0;
  padding: 1em;
  line-height: 1.3;
}
.collapsible .menu-item {
  border-left: 2px solid #888;
  border-right: 2px solid #888;
  background: linear-gradient(to bottom, #eee 0%,#ddd 100%);
}
.menu-item.toggler {
  background: linear-gradient(to bottom, #aaa 0%,#888 100%);
  color: white;
  cursor: pointer;
}
.menu-item.toggler:before {
  content: '';
  display: block;
  border-left: 8px solid white;
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  width: 0;
  height: 0;
  float: right;
  transition: transform 0.3s ease-out;
}
.menu-item.toggler.toggled:before {
  transform: rotate(90deg);
}

body { font-family: sans-serif; font-size: 14px; }

*, *:after {
  box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="container">
  <div class="menu">
    <div class="menu-item">Something involving a holodeck</div>
    <div class="menu-item">Send an away team</div>
    <div class="menu-item toggler">Advanced solutions</div>
    <div class="collapsible-wrapper collapsed">
      <div class="collapsible">
        <div class="menu-item">Separate saucer</div>
        <div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
        <div class="menu-item">Ask Worf</div>
        <div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div>
        <div class="menu-item">Ask Q for help</div>
      </div>
    </div>
    <div class="menu-item">Sweet-talk the alien aggressor</div>
    <div class="menu-item">Re-route power from auxiliary systems</div>
  </div>

  <div class="menu">
    <div class="menu-item">Something involving a holodeck</div>
    <div class="menu-item">Send an away team</div>
    <div class="menu-item toggler">Advanced solutions</div>
    <div class="collapsible-wrapper collapsed">
      <div class="collapsible">
        <div class="menu-item">Separate saucer</div>
        <div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
      </div>
    </div>
    <div class="menu-item">Sweet-talk the alien aggressor</div>
    <div class="menu-item">Re-route power from auxiliary systems</div>
  </div>

  <div class="menu">
    <div class="menu-item">Something involving a holodeck</div>
    <div class="menu-item">Send an away team</div>
    <div class="menu-item toggler">Advanced solutions</div>
    <div class="collapsible-wrapper collapsed">
      <div class="collapsible">
        <div class="menu-item">Separate saucer</div>
        <div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
        <div class="menu-item">Ask Worf</div>
        <div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div>
        <div class="menu-item">Ask Q for help</div>
        <div class="menu-item">Separate saucer</div>
        <div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
        <div class="menu-item">Ask Worf</div>
        <div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div>
        <div class="menu-item">Ask Q for help</div>
      </div>
    </div>
    <div class="menu-item">Sweet-talk the alien aggressor</div>
    <div class="menu-item">Re-route power from auxiliary systems</div>
  </div>

</div>

Как это работает?

На самом деле так и есть два переходы, связанные с тем, чтобы это произошло.Один из них переходит в margin-bottom от 0 пикселей (в развернутом состоянии) до -2000px в свернутом состоянии (аналогично этот ответ).2000 здесь - это первое магическое число, оно основано на предположении, что ваш прямоугольник не будет выше этого (2000 пикселей кажутся разумным выбором).

Используя margin-bottom переход сам по себе сопряжен с двумя проблемами:

  • Если у вас действительно есть прямоугольник размером более 2000 пикселей, то margin-bottom: -2000px не будет скрывать все - даже в свернутом корпусе будут видны детали.Это незначительное исправление, которое мы исправим позже.
  • Если фактическая высота поля, скажем, 1000 пикселей, а длина вашего перехода составляет 300 мс, то видимый переход уже завершен примерно через 150 мс (или, в противоположном направлении, начинается с опозданием на 150 мс).

Исправление этой второй проблемы заключается в том, что происходит второй переход, и этот переход концептуально нацелен на оболочку минимальный высота ("концептуально", потому что на самом деле мы не используем min-height свойство для этого;подробнее об этом позже).

Вот анимация, которая показывает, как объединение перехода нижнего поля с переходом минимальной высоты, оба с одинаковой продолжительностью, дает нам комбинированный переход от полной высоты к нулевой высоте с одинаковой продолжительностью.

animation as described above

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

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

Как вы можете видеть на анимации, результирующий переход является непрерывным, но его невозможно дифференцировать - в тот момент, когда минимальная высота равна полной высоте, скорректированной с помощью нижнего поля, происходит внезапное изменение скорости.Это очень заметно в анимации, потому что она использует линейную функцию синхронизации для обоих переходов, а также потому, что весь переход происходит очень медленно.В реальном случае (моя демонстрация вверху) переход занимает всего 300 мс, а переход с нижней границы не является линейным.Я поиграл с множеством различных функций синхронизации для обоих переходов, и те, с которыми я в итоге столкнулся, показались мне наиболее подходящими для самых разных случаев.

Осталось решить две проблемы:

  1. точка сверху, где поля высотой более 2000 пикселей не полностью скрыты в свернутом состоянии,
  2. и обратная проблема, когда в нескрытом случае поля высотой менее 50 пикселей слишком высоки, даже когда переход не выполняется, потому что минимальная высота удерживает их на уровне 50 пикселей.

Мы решаем первую проблему, предоставляя элементу контейнера max-height: 0 в свернутом корпусе, с 0s 0.3s переходный период.Это означает, что на самом деле это не переход, а max-height применяется с задержкой;это применяется только после завершения перехода.Чтобы это работало правильно, нам также нужно выбрать числовое значение max-height для противоположного, не свернутого состояния.Но в отличие от случая с разрешением 2000 пикселей, где выбор слишком большого числа влияет на качество перехода, в данном случае это действительно не имеет значения.Таким образом, мы можем просто выбрать число, которое настолько велико, что мы знать что никакая высота никогда и близко не сравнится с этой.Я выбрал миллион пикселей.Если вы считаете, что вам может понадобиться поддерживать контент высотой более миллиона пикселей, то 1) Извините и 2) просто добавьте пару нулей.

Вторая проблема - это причина, по которой мы на самом деле не используем min-height для перехода по минимальной высоте.Вместо этого существует ::after псевдоэлемент в контейнере с height это переходит от 50 пикселей к нулю.Это имеет тот же эффект, что и min-height:Это не позволит контейнеру уменьшиться ниже любой высоты, которую в данный момент имеет псевдоэлемент.Но поскольку мы используем height, не min-height, теперь мы можем использовать max-height (еще раз применяется с задержкой), чтобы установить фактическую высоту псевдоэлемента равной нулю после завершения перехода, гарантируя, что по крайней мере за пределами перехода даже небольшие элементы будут иметь правильную высоту.Потому что min-height является сильнее чем max-height, это бы не сработало, если бы мы использовали контейнер min-height вместо псевдоэлемента height.Точно так же, как max-height в предыдущем абзаце это max-height также требуется значение для противоположного конца перехода.Но в этом случае мы можем просто выбрать размер 50 пикселей.

Протестировано в Chrome (Win, Mac, Android, iOS), Firefox (Win, Mac, Android), Edge, IE11 (за исключением проблемы с макетом flexbox в моей демо-версии, которую я не утруждал отладкой) и Safari (Mac, iOS).Говоря о flexbox, должно быть возможно заставить это работать без использования какого-либо flexbox;на самом деле, я думаю, вы могли бы заставить работать почти все в IE7 - за исключением того факта, что у вас не будет CSS-переходов, что делает это довольно бессмысленным упражнением.

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

function growDiv() {
  var growDiv = document.getElementById('grow');
  if (growDiv.clientHeight) {
    growDiv.style.height = 0;
  } else {
    var wrapper = document.querySelector('.measuringWrapper');
    growDiv.style.height = wrapper.clientHeight + "px";
  }
}
#grow {
  -moz-transition: height .5s;
  -ms-transition: height .5s;
  -o-transition: height .5s;
  -webkit-transition: height .5s;
  transition: height .5s;
  height: 0;
  overflow: hidden;
  outline: 1px solid red;
}
<input type="button" onclick="growDiv()" value="grow">
<div id='grow'>
  <div class='measuringWrapper'>
    <div>
      The contents of my div.
    </div>
    <div>
      The contents of my div.
    </div>
    <div>
      The contents of my div.
    </div>
    <div>
      The contents of my div.
    </div>
    <div>
      The contents of my div.
    </div>
    <div>
      The contents of my div.
    </div>
  </div>
</div>

Хотелось бы просто иметь возможность обойтись без .measuringWrapper и просто установите высоту DIV в значение auto и сделайте анимацию, но это, похоже, не работает (высота устанавливается, но анимации не происходит).

function growDiv() {
  var growDiv = document.getElementById('grow');
  if (growDiv.clientHeight) {
    growDiv.style.height = 0;
  } else {
    growDiv.style.height = 'auto';
  }
}
#grow {
  -moz-transition: height .5s;
  -ms-transition: height .5s;
  -o-transition: height .5s;
  -webkit-transition: height .5s;
  transition: height .5s;
  height: 0;
  overflow: hidden;
  outline: 1px solid red;
}
<input type="button" onclick="growDiv()" value="grow">
<div id='grow'>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
</div>

Моя интерпретация заключается в том, что для запуска анимации необходима явная высота.Вы не можете получить анимацию по высоте, когда любая высота (начальная или конечная высота) равна auto.

Визуальный обходной путь для анимации высоты с использованием CSS3 transitions заключается в том, чтобы вместо этого анимировать заполнение.

Вы не совсем получаете полный эффект стирания, но, поиграв со значениями длительности перехода и заполнения, вы должны приблизиться к нему достаточно близко.Если вы не хотите явно устанавливать height / max-height , это должно быть то, что вы ищете.

div {
    height: 0;
    overflow: hidden;
    padding: 0 18px;
    -webkit-transition: all .5s ease;
       -moz-transition: all .5s ease;
            transition: all .5s ease;
}
div.animated {
    height: auto;
    padding: 24px 18px;
}

http://jsfiddle.net/catharsis/n5XfG/17/ (взято из статьи стивбэнда выше jsFiddle)

Мой обходной путь - перевести max-height на точную высоту содержимого для приятной плавной анимации, затем использовать обратный вызов transitionEnd, чтобы установить max-height равным 9999px, чтобы содержимое могло свободно изменять размер.

var content = $('#content');
content.inner = $('#content .inner'); // inner div needed to get size of content when closed

// css transition callback
content.on('transitionEnd webkitTransitionEnd transitionend oTransitionEnd msTransitionEnd', function(e){
    if(content.hasClass('open')){
        content.css('max-height', 9999); // try setting this to 'none'... I dare you!
    }
});

$('#toggle').on('click', function(e){
    content.toggleClass('open closed');
    content.contentHeight = content.outerHeight();
    
    if(content.hasClass('closed')){
        
        // disable transitions & set max-height to content height
        content.removeClass('transitions').css('max-height', content.contentHeight);
        setTimeout(function(){
            
            // enable & start transition
            content.addClass('transitions').css({
                'max-height': 0,
                'opacity': 0
            });
            
        }, 10); // 10ms timeout is the secret ingredient for disabling/enabling transitions
        // chrome only needs 1ms but FF needs ~10ms or it chokes on the first animation for some reason
        
    }else if(content.hasClass('open')){  
        
        content.contentHeight += content.inner.outerHeight(); // if closed, add inner height to content height
        content.css({
            'max-height': content.contentHeight,
            'opacity': 1
        });
        
    }
});
.transitions {
    transition: all 0.5s ease-in-out;
    -webkit-transition: all 0.5s ease-in-out;
    -moz-transition: all 0.5s ease-in-out;
}

body {
    font-family:Arial;
    line-height: 3ex;
}
code {
    display: inline-block;
    background: #fafafa;
    padding: 0 1ex;
}
#toggle {
    display:block;
    padding:10px;
    margin:10px auto;
    text-align:center;
    width:30ex;
}
#content {
    overflow:hidden;
    margin:10px;
    border:1px solid #666;
    background:#efefef;
    opacity:1;
}
#content .inner {
    padding:10px;
    overflow:auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<div id="content" class="open">
    <div class="inner">
        <h3>Smooth CSS Transitions Between <code>height: 0</code> and <code>height: auto</code></h3>
        <p>A clever workaround is to use <code>max-height</code> instead of <code>height</code>, and set it to something bigger than your content. Problem is the browser uses this value to calculate transition duration. So if you set it to <code>max-height: 1000px</code> but the content is only 100px high, the animation will be 10x too fast.</p>
        <p>Another option is to measure the content height with JS and transition to that fixed value, but then you have to keep track of the content and manually resize it if it changes.</p>
        <p>This solution is a hybrid of the two - transition to the measured content height, then set it to <code>max-height: 9999px</code> after the transition for fluid content sizing.</p>
    </div>
</div>

<br />

<button id="toggle">Challenge Accepted!</button>

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

Вы все еще можете выполнить фактическую анимацию с помощью CSS, но вам нужно использовать JavaScript для вычисления высоты элементов, вместо того чтобы пытаться использовать auto.jQuery не требуется, хотя вам, возможно, придется немного изменить это, если вы хотите обеспечить совместимость (работает в последней версии Chrome :)).

window.toggleExpand = function(element) {
    if (!element.style.height || element.style.height == '0px') { 
        element.style.height = Array.prototype.reduce.call(element.childNodes, function(p, c) {return p + (c.offsetHeight || 0);}, 0) + 'px';
    } else {
        element.style.height = '0px';
    }
}
#menu #list {
    height: 0px;
    transition: height 0.3s ease;
    background: #d5d5d5;
    overflow: hidden;
}
<div id="menu">
    <input value="Toggle list" type="button" onclick="toggleExpand(document.getElementById('list'));">
    <ul id="list">
        <!-- Works well with dynamically-sized content. -->
        <li>item</li>
        <li><div style="height: 100px; width: 100px; background: red;"></div></li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>

Использование max-height с различным ослаблением перехода и задержкой для каждого состояния.

HTML:

<a href="#" id="trigger">Hover</a>
<ul id="toggled">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
<ul>

CSS:

#toggled{
    max-height: 0px;
    transition: max-height .8s cubic-bezier(0, 1, 0, 1) -.1s;
}

#trigger:hover + #toggled{
    max-height: 9999px;
    transition-timing-function: cubic-bezier(0.5, 0, 1, 0); 
    transition-delay: 0s;
}

Смотрите пример: http://jsfiddle.net/0hnjehjc/1/

Никаких жестко закодированных значений.

Никакого JavaScript.

Никаких приближений.

Хитрость заключается в использовании скрытого и дублированного div чтобы заставить браузер понять, что значит 100%.

Этот метод подходит всякий раз, когда у вас есть возможность дублировать DOM элемента, который вы хотите анимировать.

.outer {
  border: dashed red 1px;
  position: relative;
}

.dummy {
  visibility: hidden;
}

.real {
  position: absolute;
  background: yellow;
  height: 0;
  transition: height 0.5s;
  overflow: hidden;
}

.outer:hover>.real {
  height: 100%;
}
Hover over the box below:
<div class="outer">
  <!-- The actual element that you'd like to animate -->
  <div class="real">
unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable
content unpredictable content unpredictable content unpredictable content
  </div>
  <!-- An exact copy of the element you'd like to animate. -->
  <div class="dummy" aria-hidden="true">
unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable
content unpredictable content unpredictable content unpredictable content
  </div>
</div>

Там было мало упоминаний о Element.scrollHeight свойство, которое может быть полезно здесь и все еще может быть использовано с чистым CSS-переходом.Свойство всегда содержит "полную" высоту элемента, независимо от того, переполняется ли его содержимое в результате уменьшения высоты (например, height: 0).

Как таковой, для height: 0 (фактически полностью свернутый) элемент, его "нормальная" или "полная" высота по-прежнему легко доступна через его scrollHeight значение (неизменно a пиксель длина).

Для такого элемента, предполагая, что у него уже настроен переход, например(используя ul согласно первоначальному вопросу):

ul {
    height: 0;
    transition: height 1s; /* An example transition. */
}

Мы можем вызвать желаемое анимированное "расширение" высоты, используя только CSS, с чем-то вроде следующего (здесь предполагается ul переменная ссылается на список):

ul.style.height = ul.scrollHeight + "px";

Вот и все.Если вам нужно свернуть список, подойдет любое из двух следующих утверждений:

ul.style.height = "0";
ul.style.removeProperty("height");

Мой конкретный вариант использования вращался вокруг анимации списков неизвестной и часто значительной длины, поэтому мне было неудобно останавливаться на произвольном "достаточно большом" значении height или max-height спецификация и риск отсечения содержимого или содержимого, которое вам внезапно понадобится прокрутить (если overflow: auto, например).Кроме того, ослабление и хронометраж нарушаются при max-height-основанные на решениях, поскольку используемая высота может достичь своего максимального значения намного раньше, чем это потребовалось бы для max-height чтобы достичь 9999px.И по мере роста разрешения экрана длина пикселей, такая как 9999px оставляешь неприятный привкус у меня во рту.На мой взгляд, это конкретное решение решает проблему элегантным образом.

Наконец, мы надеемся, что будущие редакции CSS устранят необходимость авторов делать подобные вещи еще более элегантно - пересмотреть понятие "вычисленных" по сравнению с "используемыми" и "разрешенными" значениями и рассмотреть, должны ли переходы применяться к вычисляемым значениям, включая переходы с width и height (которые в настоящее время получают немного особое отношение).

Когда я публикую это, уже есть более 30 ответов, но я чувствую, что мой ответ улучшает уже принятый ответ автор: Джейк.

Я не был доволен проблемой, которая возникает из-за простого использования max-height и CSS3-переходы, поскольку, как отметили многие комментаторы, вы должны установить свой max-height значение, очень близкое к фактической высоте, иначе вы получите задержку.Видишь это JSFiddle приведу пример этой проблемы.

Чтобы обойти это (по-прежнему не используя JavaScript), я добавил еще один HTML-элемент, который преобразует transform: translateY Значение CSS.

Это означает и то, и другое max-height и translateY используются: max-height позволяет элементу опускать элементы под собой, в то время как translateY дает желаемый "мгновенный" эффект.Проблема с max-height все еще существует, но его эффект уменьшен.Это означает, что вы можете установить гораздо большую высоту для вашего max-height меньше цените это и беспокойтесь по этому поводу.

Общее преимущество заключается в том, что при обратном переходе (сворачивании) пользователь видит translateY анимация происходит немедленно, так что на самом деле не имеет значения, как долго max-height берет.

Решение как скрипка

body {
  font-family: sans-serif;
}

.toggle {
  position: relative;
  border: 2px solid #333;
  border-radius: 3px;
  margin: 5px;
  width: 200px;
}

.toggle-header {
  margin: 0;
  padding: 10px;
  background-color: #333;
  color: white;
  text-align: center;
  cursor: pointer;
}

.toggle-height {
  background-color: tomato;
  overflow: hidden;
  transition: max-height .6s ease;
  max-height: 0;
}

.toggle:hover .toggle-height {
  max-height: 1000px;
}

.toggle-transform {
  padding: 5px;
  color: white;
  transition: transform .4s ease;
  transform: translateY(-100%);
}

.toggle:hover .toggle-transform {
  transform: translateY(0);
}
<div class="toggle">
  <div class="toggle-header">
    Toggle!
  </div>
  <div class="toggle-height">
    <div class="toggle-transform">
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
    </div>
  </div>
</div>

<div class="toggle">
  <div class="toggle-header">
    Toggle!
  </div>
  <div class="toggle-height">
    <div class="toggle-transform">
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
    </div>
  </div>
</div>

Итак, я думаю, что пришел к очень простому ответу...НЕТ max-height, использует relative позиционирование, работает над li elements, & - это чистый CSS.Я не тестировал ни в чем, кроме Firefox, хотя, судя по CSS, он должен работать во всех браузерах.

СКРИПКА: http://jsfiddle.net/n5XfG/2596/

CSS

.wrap { overflow:hidden; }

.inner {
            margin-top:-100%;
    -webkit-transition:margin-top 500ms;
            transition:margin-top 500ms;
}

.inner.open { margin-top:0px; }

HTML

<div class="wrap">
    <div class="inner">Some Cool Content</div>
</div>

Редактировать:Прокрутите вниз, чтобы найти обновленный ответ
Я составлял выпадающий список и увидел этот пост ...много разных ответов, но я решаю поделиться и своим выпадающим списком...Это не идеально, но, по крайней мере, в раскрывающемся списке будет использоваться только css!Я использовал transform:translateY (y) для преобразования списка в представление...
Вы можете увидеть больше в тесте
http://jsfiddle.net/BVEpc/4/
Я поместил div за каждым li, потому что мой выпадающий список идет сверху, и чтобы показать их должным образом, это было необходимо, мой div-код:

#menu div {
    transition: 0.5s 1s;
    z-index:-1;
    -webkit-transform:translateY(-100%);
    -webkit-transform-origin: top;
}

и наведение курсора - это :

#menu > li:hover div {
    transition: 0.5s;
    -webkit-transform:translateY(0);
}

и поскольку высота ul задана для содержимого, она может превышать содержимое вашего тела, вот почему я сделал это для ul:

 #menu ul {
    transition: 0s 1.5s;
    visibility:hidden;
    overflow:hidden;
}

и зависнуть:

#menu > li:hover ul {
     transition:none;
     visibility:visible;
}

второй раз после перехода происходит задержка, и он будет скрыт после того, как мой выпадающий список будет анимировано закрыт...
Надеюсь, позже кто-нибудь извлекет из этого пользу.

Редактировать:Я просто не могу поверить, что ppl на самом деле использует этот прототип!это выпадающее меню предназначено только для одного подменю, и это все!!Я обновил лучшее, которое может иметь два подменю как для направления ltr, так и для rtl с поддержкой IE 8.
Скрипка для LTR
Скрипка для RTL
надеюсь, кому-нибудь это пригодится в будущем.

Вы можете перейти от height:0 к height: auto при условии, что вы также укажете min-height и max-height.

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}

Решение Flexbox

Плюсы:

  • простой
  • нет JS
  • плавный переход

Минусы:

  • элемент необходимо поместить в гибкий контейнер фиксированной высоты

Способ, которым это работает, заключается в том, что всегда используется гибкая основа:автоматически для элемента с содержимым и вместо этого переключает flex-grow и flex-shrink.

Редактировать:Улучшенный JS Fiddle, вдохновленный интерфейсом Xbox One.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  transition: 0.25s;
  font-family: monospace;
}

body {
  margin: 10px 0 0 10px;
}

.box {
  width: 150px;
  height: 150px;
  margin: 0 2px 10px 0;
  background: #2d333b;
  border: solid 10px #20262e;
  overflow: hidden;
  display: inline-flex;
  flex-direction: column;
}

.space {
  flex-basis: 100%;
  flex-grow: 1;
  flex-shrink: 0;    
}

p {
  flex-basis: auto;
  flex-grow: 0;
  flex-shrink: 1;
  background: #20262e;
  padding: 10px;
  width: 100%;
  text-align: left;
  color: white;
}

.box:hover .space {
  flex-grow: 0;
  flex-shrink: 1;
}
  
.box:hover p {
  flex-grow: 1;
  flex-shrink: 0;    
}
<div class="box">
  <div class="space"></div>
  <p>
    Super Metroid Prime Fusion
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Resident Evil 2 Remake
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Yolo The Game
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Final Fantasy 7 Remake + All Additional DLC + Golden Tophat
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    DerpVille
  </p>
</div>

JS Скрипка

Я думаю, что нашел действительно надежное решение

Хорошо!Я знаю, что эта проблема так же стара, как интернет, но я думаю, что у меня есть решение, которое я превратил в плагин под названием mutant-transition.Мое решение устанавливает style="" атрибуты для отслеживаемых элементов при каждом изменении в DOM.конечным результатом является то, что вы можете использовать хороший ole CSS для своих переходов и не использовать хакерские исправления или специальный javascript.Единственное, что вам нужно сделать, это установить, что вы хотите отслеживать в рассматриваемом элементе, используя data-mutant-attributes="X".

<div data-mutant-attributes="height">                                                                      
        This is an example with mutant-transition                                                                                                          
    </div>

Вот и все!Это решение использует Наблюдатель мутаций следить за изменениями в DOM.Из-за этого вам на самом деле не нужно ничего настраивать или использовать javascript для ручной анимации объектов.Изменения отслеживаются автоматически.Однако, поскольку он использует MutationObserver, это приведет к переходу только в IE11 +.

Скрипки!

Вот способ перехода от любой начальной высоты, включая 0, к автоматической (полноразмерной и гибкой), не требуя жестко заданного кода для каждого узла или какого-либо пользовательского кода для инициализации: https://github.com/csuwildcat/transition-auto.Я верю, что это, по сути, святой грааль для того, чего вы хотите ...> http://codepen.io/csuwldcat/pen/kwsdF.Просто вставьте следующий JS-файл на свою страницу, и все, что вам нужно сделать после этого, это добавить / удалить один логический атрибут - reveal="" - из узлов, которые вы хотите расширять и сжимать.

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

/*** Nothing out of the ordinary in your styles ***/
<style>
    div {
        height: 0;
        overflow: hidden;
        transition: height 1s;
    }
</style>

/*** Just add and remove one attribute and transition to/from auto! ***/

<div>
    I have tons of content and I am 0px in height you can't see me...
</div>

<div reveal>
     I have tons of content and I am 0px in height you can't see me...
     but now that you added the 'reveal' attribute, 
     I magically transitioned to full height!...
</div>

Вот блок кода для включения на вашу страницу, после этого все готово:

Поместите этот JS-файл на свою страницу - все просто работает ™

/* Код для обозначения высоты:автоматический;переходящий */

(function(doc){

/* feature detection for browsers that report different values for scrollHeight when an element's overflow is hidden vs visible (Firefox, IE) */
var test = doc.documentElement.appendChild(doc.createElement('x-reveal-test'));
    test.innerHTML = '-';
    test.style.cssText = 'display: block !important; height: 0px !important; padding: 0px !important; font-size: 0px !important; border-width: 0px !important; line-height: 1px !important; overflow: hidden !important;';
var scroll = test.scrollHeight || 2;
doc.documentElement.removeChild(test);

var loading = true,
    numReg = /^([0-9]*\.?[0-9]*)(.*)/,
    skipFrame = function(fn){
      requestAnimationFrame(function(){
        requestAnimationFrame(fn);
      });
    },
    /* 2 out of 3 uses of this function are purely to work around Chrome's catastrophically busted implementation of auto value CSS transitioning */
    revealFrame = function(el, state, height){
        el.setAttribute('reveal-transition', 'frame');
        el.style.height = height;
        skipFrame(function(){
            el.setAttribute('reveal-transition', state);
            el.style.height = '';
        });
    },
    transitionend = function(e){
      var node = e.target;
      if (node.hasAttribute('reveal')) {
        if (node.getAttribute('reveal-transition') == 'running') revealFrame(node, 'complete', '');
      } 
      else {
        node.removeAttribute('reveal-transition');
        node.style.height = '';
      }
    },
    animationstart = function(e){
      var node = e.target,
          name = e.animationName;   
      if (name == 'reveal' || name == 'unreveal') {

        if (loading) return revealFrame(node, 'complete', 'auto');

        var style = getComputedStyle(node),
            offset = (Number(style.paddingTop.match(numReg)[1])) +
                     (Number(style.paddingBottom.match(numReg)[1])) +
                     (Number(style.borderTopWidth.match(numReg)[1])) +
                     (Number(style.borderBottomWidth.match(numReg)[1]));

        if (name == 'reveal'){
          node.setAttribute('reveal-transition', 'running');
          node.style.height = node.scrollHeight - (offset / scroll) + 'px';
        }
        else {
            if (node.getAttribute('reveal-transition') == 'running') node.style.height = '';
            else revealFrame(node, 'running', node.scrollHeight - offset + 'px');
        }
      }
    };

doc.addEventListener('animationstart', animationstart, false);
doc.addEventListener('MSAnimationStart', animationstart, false);
doc.addEventListener('webkitAnimationStart', animationstart, false);
doc.addEventListener('transitionend', transitionend, false);
doc.addEventListener('MSTransitionEnd', transitionend, false);
doc.addEventListener('webkitTransitionEnd', transitionend, false);

/*
    Batshit readyState/DOMContentLoaded code to dance around Webkit/Chrome animation auto-run weirdness on initial page load.
    If they fixed their code, you could just check for if(doc.readyState != 'complete') in animationstart's if(loading) check
*/
if (document.readyState == 'complete') {
    skipFrame(function(){
        loading = false;
    });
}
else document.addEventListener('DOMContentLoaded', function(e){
    skipFrame(function(){
        loading = false;
    });
}, false);

/* Styles that allow for 'reveal' attribute triggers */
var styles = doc.createElement('style'),
    t = 'transition: none; ',
    au = 'animation: reveal 0.001s; ',
    ar = 'animation: unreveal 0.001s; ',
    clip = ' { from { opacity: 0; } to { opacity: 1; } }',
    r = 'keyframes reveal' + clip,
    u = 'keyframes unreveal' + clip;

styles.textContent = '[reveal] { -ms-'+ au + '-webkit-'+ au +'-moz-'+ au + au +'}' +
    '[reveal-transition="frame"] { -ms-' + t + '-webkit-' + t + '-moz-' + t + t + 'height: auto; }' +
    '[reveal-transition="complete"] { height: auto; }' +
    '[reveal-transition]:not([reveal]) { -webkit-'+ ar +'-moz-'+ ar + ar +'}' +
    '@-ms-' + r + '@-webkit-' + r + '@-moz-' + r + r +
    '@-ms-' + u +'@-webkit-' + u + '@-moz-' + u + u;

doc.querySelector('head').appendChild(styles);

})(document);

/* Код для ДЕМО-версии */

    document.addEventListener('click', function(e){
      if (e.target.nodeName == 'BUTTON') {
        var next = e.target.nextElementSibling;
        next.hasAttribute('reveal') ? next.removeAttribute('reveal') : next.setAttribute('reveal', '');
      }
    }, false);

Ответ Джейка на анимацию максимальной высоты отличный, но я обнаружил, что задержка, вызванная установкой большой максимальной высоты, раздражает.

Можно было бы переместить сворачиваемое содержимое во внутренний div и вычислить максимальную высоту, получив высоту внутреннего div (через jQuery это была бы outerHeight ()).

$('button').bind('click', function(e) { 
  e.preventDefault();
  w = $('#outer');
  if (w.hasClass('collapsed')) {
    w.css({ "max-height": $('#inner').outerHeight() + 'px' });
  } else {
    w.css({ "max-height": "0px" });
  }
  w.toggleClass('collapsed');
});

Вот ссылка на jsfiddle: http://jsfiddle.net/pbatey/duZpT

Вот jsfiddle с абсолютно минимальным объемом требуемого кода: http://jsfiddle.net/8ncjjxh8/

Расширяя ответ @jake, переход будет проходить до максимального значения высоты, вызывая чрезвычайно быструю анимацию - если вы установите переходы для обоих режимов: наведение и выключение, вы сможете немного больше контролировать сумасшедшую скорость.

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

Надеюсь, это вам хоть как-то поможет.

например,:

.sidemenu li ul {
   max-height: 0px;
   -webkit-transition: all .3s ease;
   -moz-transition: all .3s ease;
   -o-transition: all .3s ease;
   -ms-transition: all .3s ease;
   transition: all .3s ease;
}
.sidemenu li:hover ul {
    max-height: 500px;
    -webkit-transition: all 1s ease;
   -moz-transition: all 1s ease;
   -o-transition: all 1s ease;
   -ms-transition: all 1s ease;
   transition: all 1s ease;
}
/* Adjust speeds to the possible height of the list */

Вот скрипка: http://jsfiddle.net/BukwJ/

Я понимаю, что эта тема устарела, но она занимает высокое место в некоторых поисковых системах Google, поэтому я считаю, что ее стоит обновить.

Вы также просто получаете / устанавливаете собственную высоту элемента:

var load_height = document.getElementById('target_box').clientHeight;
document.getElementById('target_box').style.height = load_height + 'px';

Вы должны сбросить этот Javascript сразу после закрывающего тега target_box во встроенном теге script.

Я смог это сделать.У меня есть .child & a .parent див.Дочерний div идеально вписывается в родительскую ширину / высоту с absolute позиционирование.Затем я анимирую translate свойство подталкивать его к Y значение снижается 100%.Его очень плавная анимация, никаких сбоев или недостатков, как у любого другого решения здесь.

Что-то вроде этого, псевдокод

.parent{ position:relative; overflow:hidden; } 
/** shown state */
.child {
  position:absolute;top:0;:left:0;right:0;bottom:0;
  height: 100%;
  transition: transform @overlay-animation-duration ease-in-out;
  .translate(0, 0);
}

/** Animate to hidden by sliding down: */
.child.slidedown {
  .translate(0, 100%); /** Translate the element "out" the bottom of it's .scene container "mask" so its hidden */
}

Вы бы указали height вкл . .parent, в px, %, или оставить как есть auto.Затем этот div маскирует .child div, когда он скользит вниз.

Вот решение, которое я только что использовал в сочетании с jQuery.Это работает для следующей HTML-структуры:

<nav id="main-nav">
    <ul>
        <li>
            <a class="main-link" href="yourlink.html">Link</a>
            <ul>
                <li><a href="yourlink.html">Sub Link</a></li>
            </ul>
        </li>
    </ul>
</nav>

и функция:

    $('#main-nav li ul').each(function(){
        $me = $(this);

        //Count the number of li elements in this UL
        var liCount = $me.find('li').size(),
        //Multiply the liCount by the height + the margin on each li
            ulHeight = liCount * 28;

        //Store height in the data-height attribute in the UL
        $me.attr("data-height", ulHeight);
    });

Затем вы могли бы использовать функцию click для установки и удаления высоты с помощью css()

$('#main-nav li a.main-link').click(function(){
    //Collapse all submenus back to 0
    $('#main-nav li ul').removeAttr('style');

    $(this).parent().addClass('current');

    //Set height on current submenu to it's height
    var $currentUl = $('li.current ul'),
        currentUlHeight = $currentUl.attr('data-height');
})

CSS:

#main-nav li ul { 
    height: 0;
    position: relative;
    overflow: hidden;
    opacity: 0; 
    filter: alpha(opacity=0); 
    -ms-filter: "alpha(opacity=0)";
    -khtml-opacity: 0; 
    -moz-opacity: 0;
    -webkit-transition: all .6s ease-in-out;
    -moz-transition: all .6s ease-in-out;
    -o-transition: all .6s ease-in-out;
    -ms-transition: all .6s ease-in-out;
    transition: all .6s ease-in-out;
}

#main-nav li.current ul {
    opacity: 1.0; 
    filter: alpha(opacity=100); 
    -ms-filter: "alpha(opacity=100)";
    -khtml-opacity: 1.0; 
    -moz-opacity: 1.0;
}

.ie #main-nav li.current ul { height: auto !important }

#main-nav li { height: 25px; display: block; margin-bottom: 3px }

Недавно я перешел на max-height на li элементы, а не обертка ul.

Причина заключается в том, что задержка для небольших max-heights гораздо менее заметен (если вообще заметен) по сравнению с большими max-heights, и я также могу установить свой max-height значение относительно font-size из числа li вместо какого-то произвольного огромного числа с помощью ems или rems.

Если мой размер шрифта равен 1rem, я установлю свой max-height к чему - то вроде 3rem (для размещения обернутого текста).Вы можете увидеть пример здесь:

http://codepen.io/mindfullsilence/pen/DtzjE

Я не читал все подробно, но недавно у меня возникла эта проблема, и я сделал следующее:

div.class{
   min-height:1%;
   max-height:200px;
   -webkit-transition: all 0.5s ease;
   -moz-transition: all 0.5s ease;
   -o-transition: all 0.5s ease;
   -webkit-transition: all 0.5s ease;
   transition: all 0.5s ease;
   overflow:hidden;
}

div.class:hover{
   min-height:100%;
   max-height:3000px;
}

Это позволяет вам иметь div, который сначала показывает содержимое высотой до 200 пикселей, а при наведении курсора мыши его размер становится, по крайней мере, таким же высоким, как все содержимое div.Div не становится размером 3000px, но 3000px - это ограничение, которое я устанавливаю.Убедитесь, что переход выполнен без наведения курсора мыши, иначе вы можете получить какой-то странный рендеринг.Таким образом, параметр :hover наследуется от параметра non :hover.

Переход не работает из px в % или в auto.Вам нужно использовать ту же единицу измерения.У меня это прекрасно работает.Использование HTML5 делает его идеальным....

Помните, что всегда есть обходной путь...;)

Надеюсь, кто-нибудь найдет это полезным

Это не совсем "решение" проблемы, скорее обходной путь.Он работает только так, как написано с текстом, но, я уверен, может быть изменен для работы с другими элементами по мере необходимости.

.originalContent {
    font-size:0px;
    transition:font-size .2s ease-in-out;
}
.show { /* class to add to content */
    font-size:14px;
}

Вот такой пример: http://codepen.io/overthemike/pen/wzjRKa

По сути, вы устанавливаете размер шрифта равным 0 и переходите к нему вместо height, или max-height, или scaleY() и т.д.в достаточно быстром темпе, чтобы высота трансформировалась в то, что вы хотите.Преобразовать фактическую высоту с помощью CSS в auto в настоящее время невозможно, но преобразование содержимого внутри возможно, отсюда переход к размеру шрифта.

  • Примечание - в codepen есть javascript, но его единственная цель - добавлять / удалять css-классы по щелчку для аккордеона.Это можно сделать с помощью скрытых переключателей, но я сосредоточился не на этом, а только на преобразовании высоты.

Я понимаю, что вопрос требует решения без JavaScript.Но для тех, кому интересно, вот мое решение, использующее совсем немного JS.

итак, css элемента, высота которого будет изменяться по умолчанию, имеет значение height: 0; и когда открыт height: auto;.В нем также есть transition: height .25s ease-out;.Но, конечно, проблема в том, что он не будет переходить ни в, ни из height: auto;

Итак, что я сделал, так это при открытии или закрытии установил высоту на scrollHeight свойство элемента.Этот новый встроенный стиль будет иметь более высокую специфичность и переопределит оба варианта height: auto; и height: 0; и переход продолжается.

При открытии я добавляю transitionend прослушиватель событий, который будет запущен только один раз, затем удалите встроенный стиль, установив его обратно на height: auto; который позволит изменять размер элемента при необходимости, как в этом более сложном примере с подменю https://codepen.io/ninjabonsai/pen/GzYyVe

При закрытии я удаляю встроенный стиль сразу после следующего цикл событий выполняйте цикл с помощью setTimeout без задержки.Это означает height: auto; временно переопределяется, что позволяет перейти обратно к height 0;

const showHideElement = (element, open) => {
  element.style.height = element.scrollHeight + 'px';
  element.classList.toggle('open', open);

  if (open) {
    element.addEventListener('transitionend', () => {
      element.style.removeProperty('height');
    }, {
      once: true
    });
  } else {
    window.setTimeout(() => {
      element.style.removeProperty('height');
    });
  }
}

const menu = document.body.querySelector('#menu');
const list = document.body.querySelector('#menu > ul')

menu.addEventListener('mouseenter', () => showHideElement(list, true));
menu.addEventListener('mouseleave', () => showHideElement(list, false));
#menu>ul {
  height: 0;
  overflow: hidden;
  background-color: #999;
  transition: height .25s ease-out;
}

#menu>ul.open {
  height: auto;
}
<div id="menu">
  <a>hover me</a>
  <ul>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
  </ul>
</div>

Решение для определения максимальной высоты от Jake работает хорошо, если жестко запрограммированное указанное значение максимальной высоты не намного больше реальной высоты (поскольку в противном случае возникают нежелательные задержки и проблемы с синхронизацией).С другой стороны, если случайно жестко заданное значение не больше реальной высоты, элемент не откроется полностью.

Следующее решение только для CSS также требует жестко заданного размера, который должен быть больше большинства существующих реальных размеров.Однако это решение также работает, если реальный размер в некоторых ситуациях больше, чем жестко заданный размер.В этом случае переход может немного измениться, но он никогда не оставит частично видимый элемент.Таким образом, это решение также может быть использовано для неизвестного контента, напримерот база данных, где вы просто знаете, что контент-это, как правило, не больше чем точек, но бывают и исключения.

Идея состоит в том, чтобы использовать отрицательное значение для margin-bottom (или margin-top для слегка отличающейся анимации) и поместить элемент содержимого в средний элемент с overflow:hidden.Отрицательное поле элемента content , таким образом, уменьшает высоту среднего элемента.

Следующий код использует переход по нижнему краю от -150px к 0px.Только это работает нормально до тех пор, как элемент содержания не превышает 150 пикселей.Кроме того, он использует переход по максимальной высоте для среднего элемента от 0 пикселей до 100%.Это окончательно скроет средний элемент если размер элемента содержимого превышает 150 пикселей.Для максимальной высоты переход используется только для задержки его применения на секунду при закрытии, а не для плавного визуального эффекта ( и, следовательно, он может работать от 0px до 100%).

CSS:

.content {
  transition: margin-bottom 1s ease-in;
  margin-bottom: -150px;
}
.outer:hover .middle .content {
  transition: margin-bottom 1s ease-out;
  margin-bottom: 0px
}
.middle {
  overflow: hidden;
  transition: max-height .1s ease 1s;
  max-height: 0px
}
.outer:hover .middle {
  transition: max-height .1s ease 0s;
  max-height: 100%
}

HTML:

<div class="outer">
  <div class="middle">
    <div class="content">
      Sample Text
      <br> Sample Text
      <br> Sample Text
      <div style="height:150px">Sample Test of height 150px</div>
      Sample Text
    </div>
  </div>
  Hover Here
</div>

Значение нижнего поля должно быть отрицательным и как можно ближе к реальной высоте элемента содержимого.Если оно (значение absoute ) больше, возникают аналогичные проблемы с задержкой и синхронизацией, как и в случае с решениями с максимальной высотой, которые, однако, могут быть ограничены до тех пор, пока жестко заданный размер не намного больше реального.Если абсолютное значение для margin-bottom меньше реальной высоты, то натяжение немного подскакивает.В любом случае после перехода элемент содержимого либо полностью отображается, либо полностью удаляется.

Более подробную информацию смотрите в моем блоге http://www.taccgl.org/blog/css_transition_display.html#combined_height

Кажется, правильного решения нет. max-height подход довольно хорош, но плохо работает на этапе скрытия - будет заметная задержка, если вы не знаете высоту содержимого.

Я думаю, что лучший способ - это использовать max-height но только на этапе показа.И не использовать никакой анимации при скрытии.В большинстве случаев это не должно быть критичным.

max-height должно быть установлено довольно большое значение, чтобы гарантировать соответствие любого контента.Скоростью анимации можно управлять с помощью transition продолжительность (speed = max-height / duration).Скорость не зависит от размера контента.Время, необходимое для отображения всего содержимого, будет зависеть от его размера.

document.querySelector("button").addEventListener(
  "click", 
  function(){
    document.querySelector("div").classList.toggle("hide");
  }
)
div {    
    max-height: 20000px;
    transition: max-height 3000ms;
    overflow-y: hidden;
}

.hide {
    max-height: 0;
    transition: none;
}
<button>Toggle</button>
<div class="hide">Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. 
</div>

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top