Как переместить высоту: 0; высота: авто; используя CSS?

Я пытаюсь сделать слайд <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>

Ответ 1

Используйте 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 to see the timing. -->
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>

Ответ 2

Вместо этого вы должны использовать 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 вместо высоты, http://jsfiddle.net/dotnetCarpenter/7cnfc/206/.

Ответ 3

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

Ответ 4

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

Ответ 5

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

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

Demo

Вот демо с тремя разборными элементами, все разные высоты, которые используют один и тот же 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 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 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 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 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>

Ответ 6

Вы можете, с небольшим количеством не-семантического jiggery-pokery. Мой обычный подход состоит в том, чтобы анимировать высоту внешнего 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>

Ответ 7

Визуальное обходное решение для анимации высоты с использованием переходов CSS3 - это анимировать дополнение.

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

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/ (сфокусирован на stefband выше jsFiddle)

Ответ 8

Мое обходное решение - переход 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>

Ответ 9

Принятый ответ работает в большинстве случаев, но он не очень хорошо работает, когда ваш 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>

Ответ 10

Используйте 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/

Ответ 11

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

Нет 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>

Ответ 12

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

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

Для такого элемента, предполагая, что он уже имеет переход, подобный, например, (используя 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 -based, поскольку используемая высота может достигать своего максимального значения намного раньше, чем потребовалось бы для max-height до 9999px. И по мере того, как разрешение экрана растет, длина пикселей, таких как 9999px оставляет 9999px неприятный вкус во рту. Это конкретное решение, на мой взгляд, решает проблему элегантным образом.

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

Ответ 13

Поскольку я публикую это, есть уже более 30 ответов, но я чувствую, что мой ответ улучшается на уже принятом ответе от jake.

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

Ответ 14

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

FIDDLE: 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>

Ответ 15

РЕДАКТИРОВАТЬ: прокрутите вниз, чтобы получить обновленный ответ
Я делал выпадающий список и видел этот пост... много разных ответов, но я решил поделиться своим выпадающим списком тоже... Он не идеален, но по крайней мере он будет использовать только 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 установлен на содержимое, которое он может получить поверх содержимого вашего тела, вот почему я сделал это для ul:

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

и зависать:

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

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

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

Ответ 16

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

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

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

Ответ 17

Решение Flexbox

Плюсы:

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

Минусы:

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

Способ, которым он работает, - это всегда иметь гибкую основу: auto на элементе с контентом и вместо этого переходить на гибкий рост и гибкую усадку.

Редактировать: Улучшенная сценарий JS, вдохновленная интерфейсом 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>

Ответ 18

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

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

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

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

скрипки!

Ответ 19

Вы должны использовать 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/

Ответ 20

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

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

Надеюсь, это поможет.

например:

.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/

Ответ 21

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

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

$('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/

Ответ 22

Здесь вы можете перейти от любой начальной высоты, включая 0, к авто (полный размер и гибкость), не требуя жесткого кода на основе node или любого пользовательского кода для инициализации: 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 файл на своей странице - все это Just Works ™

/ * Код для высоты: авто; переход */

(function(doc){

/* feature detection for browsers that report different values for scrollHeight when an element 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 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 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);

/ * Код для DEMO */

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

Ответ 23

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

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

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

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

Ответ 24

Я смог это сделать. У меня есть div .child и .parent. Детский div отлично вписывается в родительскую ширину/высоту с позиционированием absolute. Затем я анимирую свойство translate, чтобы нажать его Y значение down 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 .scene container "mask" so its hidden */
}

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

Ответ 25

Здесь решение, которое я использовал только в сочетании с 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);
    });

Затем вы можете использовать функцию щелчка для установки и удаления высоты с помощью 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 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 }

Ответ 26

Недавно я перешел на 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

Ответ 27

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

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 наследуется от не-зависания.

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

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

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

Ответ 28

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

.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 и переходите к тому, чтобы вместо высоты, или max-height или scaleY() и т.д. достаточно быстро, чтобы получить высоту, чтобы преобразовать ее в нужную вам. Чтобы преобразовать фактическую высоту с помощью CSS в auto, в настоящее время невозможно, но преобразование содержимого внутри - это, следовательно, переход размера шрифта.

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

Ответ 29

Я понимаю, что вопрос требует решения без 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>

Ответ 30

Я считаю, что решение height:auto/max-height будет работать только в том случае, если вы расширяете область больше, чем height, которую вы хотите ограничить.

Если у вас есть max-height из 300px, но выпадающее окно со списком, которое может возвращать 50px, то max-height вам не поможет, 50px является переменной в зависимости от количества элементов, вы можете прийти в невозможную ситуацию, когда я не могу ее исправить, потому что height не фиксирован, height:auto было решением, но я не могу использовать переходы с этим.