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

2136

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

Hailwood
источник
Я считаю, что height:auto/max-heightрешение будет работать, только если вы расширяете область, которая больше, чем heightвы хотите ограничить. Если у вас есть max-heightоф 300px, но выпадающий список со списком, который может вернуться 50px, а затем вам max-heightне поможет, 50pxзависит от количества элементов, вы можете оказаться в невозможной ситуации, когда я не могу это исправить, потому что heightнет Исправлено, height:autoбыло решение, но я не могу использовать переходы с этим.
Кристофер Томас
51
OP пытается найти решение css, а не js, иначе они могут просто использовать переполнение и анимировать
Тони Ли,
5
@VIDesignz: Но внутреннее поле -100% margin-top получает ширину div-оболочки, а не высоту. Таким образом, это решение имеет ту же проблему, что и решение с максимальной высотой. Более того, когда ширина меньше высоты содержимого, не все содержимое скрыто на -100% margin-top. Так что это неправильное решение.
GregTom
1
См. Github.com/w3c/csswg-drafts/issues/626 для обсуждения спецификации и реализации правильного решения
Ben

Ответы:

2747

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

Джейк
источник
324
это прекрасно работает! кроме того, есть задержка, когда он запускается, потому что он запускается для максимальной высоты, которая изначально очень высока .. хм, я думаю, что это несколько раздражает
vsync
175
+1 Отличное решение! Скорость перехода вычисляется как время, указанное вами для перехода к значению max-height ... но поскольку высота будет меньше, чем max-height, переход к фактической высоте будет происходить быстрее (часто значительно), чем Время указано.
Kingjeffrey
50
Обратите внимание, что это может привести к некрасивому завершению перехода, когда вам придется использовать значения, которые намного больше, чем фактическое вычисленное значение. Я заметил это, пытаясь увеличить div от высоты 0 до высоты содержимого, которая сильно варьируется из-за разных размеров экрана (2 строки на моем мониторе 2560x1440 против> 10 строк на смартфоне). Для этого я закончил с JS.
jpeltoniemi
44
Очень некрасивое решение, поскольку оно создает задержку в одном направлении, но не в другом.
Тим
84
Это довольно ленивое решение. Я предполагаю, что OP хочет использовать height: auto, потому что увеличенная высота контейнера несколько непредсказуема. Это решение вызовет задержку, прежде чем анимация станет видимой. Кроме того, видимая продолжительность анимации будет непредсказуемой. Вы получите гораздо более предсказуемые (и, вероятно, более плавные) результаты, рассчитав суммарную высоту каждого из дочерних узлов контейнеров, а затем снизив до точного значения высоты.
Шон Уиннери
314

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

ul {
  background-color: #eee;
  transform: scaleY(0);    
  transform-origin: top;
  transition: transform 0.26s ease;
}
p:hover ~ ul {
  transform: scaleY(1);
}
<p>Hover This</p>
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>

Я сделал версию вышеуказанного кода с префиксом поставщика на jsfiddle , и изменил ваш jsfiddle, чтобы использовать scaleY вместо height.

dotnetCarpenter
источник
6
Я одобряю этот ответ, потому что он хорошо работает в браузерах с поддержкой css3-transition, но следует отметить, что это не будет работать вообще в IE <9 , и не будет анимированным (он просто будет прыгать) в IE <10
Hailwood
215
Этот метод только частично достигает желаемого эффекта, но фактически не удаляет пространство. Преобразованная коробка действует как относительно позиционированный элемент - пространство занимает независимо от того, как оно масштабируется. Проверьте этот jsFiddle, который берет ваш первый и просто добавляет поддельный текст внизу. Обратите внимание, что текст под ним не перемещается вверх, когда высота поля масштабируется до нуля.
animuson
9
Теперь он работает: jsfiddle.net/gNDX3/1 По сути, вам нужно стилизовать элементы в соответствии с вашими потребностями. В CSS / HTML нет поведения, напоминающего серебряную пулю или виджет.
dotnetCarpenter
70
Хотя я аплодирую кому-то, пытающемуся использовать разные подходы, реальный эффект и сложности, которые приносит это решение, намного хуже, чем и без того ужасный взлом на максимальной высоте. Пожалуйста, не используйте.
Mystrdat
2
@SquareCat все в порядке, все в порядке. Вот что больше похоже на ящик: jsfiddle.net/dotnetCarpenter/WTL2r
dotnetCarpenter
202

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

robertc
источник
12
Обычно существует несколько способов решения проблемы, и не все из них являются подходящими или возможными. Я не знаю, почему @JedidiahHurt и Ryan Ore пытаются ограничить возможные ответы на сайте вопросов и ответов. Особенно учитывая, что этот ответ был здесь первым. Вдвойне, так как принятый ответ - это обходной путь.
Ура, я помогаю
5
Ответ @jake не является ни элегантным, ни правильным. Связанный ответ здесь намного лучше. Он работает правильно и обрабатывает все случаи размера - ни один не может быть сказано о принятом ответе.
GraphicsMuncher
5
Да, это такthis.$element[dimension](this.$element[dimension]())[0].offsetHeight
Энди
4
Это планируется как-то исправить? Я имею в виду, что вполне естественно ожидать возможности перехода с 0 высоты на auto...
Августин Ридингер
6
@Meliodas "нет / вы не можете" является действительным и приемлемым ответом на вопросы о переполнении стека.
TylerH
122

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

Стивен Вачон
источник
Работал аккуратно для меня. Не совсем как jQuery slideUp / Down. Вы можете увидеть разницу только со слабыми процессорами, такими как старые компьютеры или мобильные устройства, и открыв и закрыв многие из них одновременно.
Круз Нуньес
3
Если у вас есть кнопки или любые другие нетекстовые элементы, вы получите нежелательный пробел, не зависая.
Деннис W
3
Вы можете уточнить его, выбрав все дочерние элементы *и применив другие изменения. Однако мой код должен был затронуть кнопки, если они были правильно оформлены em.
Стивен Вачон
1
В моем случае мне также нужно было добавить line-height: 0;иborder-width: 0;
Андрей Шатилов
1
Вам не нужно корректировать, line-heightесли вы правильно избегаете единиц в значении: developer.mozilla.org/en-US/docs/Web/CSS/…
Стивен
93

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

  • В начале отсрочки нет, и переход не прекращается рано. В обоих направлениях (разворачивание и свертывание), если в CSS указать длительность перехода 300 мс, переход занимает 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из 0px (в расширенном состоянии) -2000pxв свернутое состояние (аналогично этому ответу ). 2000 здесь - первое магическое число, оно основано на предположении, что ваша коробка не будет выше этой (2000 пикселей кажется разумным выбором).

Использование margin-bottomодного перехода само по себе имеет две проблемы:

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

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

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

анимация как описано выше

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

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

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

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

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

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

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

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

balpha
источник
36
Я хотел бы, чтобы вы могли сократить (упростить) свое решение или хотя бы пример кода - похоже, что 90% примера кода не имеет отношения к вашему ответу.
Джил Эпштейн
Есть ли способ заставить эти переходы также работать, если collapsible-wrapperимеет абсолютную позицию. overflow: hiddenНа родителя требуется для перехода , но препятствует абсолютно позиционируемых элементов.
pmkro
1
@pmkro Да, у меня тоже была эта проблема. Я решил это с помощью clip-path: polygon(...)вместо overflow: hidden, потому что в отличие от последнего, вы можете переходить первый. В качестве запасного варианта для старых браузеров я использовал дополнительное преобразование масштабирования. См. Комментарий в верхней части github.com/StackExchange/Stacks/blob/develop/lib/css/components/…
balpha
2
Ницца. Это работает очень хорошо. Должен быть принятый ответ
Генри Инг-Симмонс
84

Вы можете, с небольшим количеством несемантических 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>

Хотелось бы просто иметь возможность обойтись без .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.

jhurshman
источник
10
Так как это зависит от javascript, вы также можете легко добавить measureWrapper, используя также javascript!
Quickredfox,
18
Вы можете сделать это без оболочки. Просто: function growDiv () {var growDiv = document.getElementById ('grow'); if (growDiv.clientHeight) {growDiv.style.height = 0; } else {growDiv.style.height = growDiv.scrollHeight + 'px'; }}
user1742529
8
Проверьте это ... поговорите о простом ответе jsfiddle.net/n5XfG/2596 ... Ваш ответ безумно сложен без веской причины. Нет необходимости max-height, нет необходимости auto, и особенно нет необходимости в Javascript! Просто две простые декларации
VIDesignz
12
@ VIDesignz Вы оживляете за маржу: 100%. Это 100% ширины элемента, а не его высоты! Это означает, что если у вас есть элемент с высотой, превышающей его ширину, это не скроет его. Кроме того, фактическая скорость анимации полностью отличается от той, которая определена.
Тимо Тюршман
3
Я был взволнован ответом VIDesignz, пока не прочитал больше о комментарии Тимо. Да, margin-topmargin-bottom) относятся к ширине, когда она определена в процентах, да, это глупо, но это также объясняет, почему время анимации открытия и закрытия совершенно различно - это то же самое, что вы видите в ответе с самым высоким рейтингом, указывая жесткий максимальная высота Почему это так сложно сделать правильно?
Coderer
52

Визуальное обходное решение для анимации высоты с использованием 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/ (сброшенный Stephband выше jsFiddle)

Катарсис
источник
3
Я думаю, что это лучший ответ. Эта техника может распространяться и на детей. В моем случае я смог объединить это с явными переходами по высоте для некоторого раскрываемого содержимого, и общий эффект гораздо более успешен, чем обход максимальной высоты, что хорошо для раскрытия, но вводит неловкий момент задержка на спрятаться Раньше я бы вообще не оживлял, чем вводил бы бессмысленную задержку, из-за которой мое приложение казалось бы не отвечающим. Я удивлен, что многие люди считают это приемлемым.
точка с запятой
17
За исключением того, что здесь вы вообще не анимируете высоту. Вы анимируете заполнение ... оно может просто исчезнуть, потому что оно может анимироваться из текущего состояния до 0, но если вы внимательно посмотрите, когда оно расширяется, оно откроется с текстом, а затем заполнение только оживит .. потому что это не не знаю, как анимировать от 0 до авто .... ему нужен числовой диапазон ... вот как работает анимация движения.
Роб Р
Это хороший обходной путь, который не является хакерским. Это не лучший ответ на этот вопрос, но это альтернатива, которая сработала для меня. Иногда вам просто нужен эффект некоторой анимации высоты, а не полная анимация :)
Иван Дерст
Это решение также дает сбой при использовании задержки перехода.
Мишель Жоанисс
Я также согласен с тем, что это решение - чистый обходной путь, который обеспечивает довольно плавные переходы, если ваша анимация достаточно быстра (в моем случае для аккордеона с переходами 0,1 с это идеально!). Хотя он не подойдет для многих приложений, но и другие ответы на этот вопрос не подойдут!
Реми Д
46

Мой обходной путь - перевести 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>

Адам
источник
14
@ Derija93 Это использует простые старые анимации тайм-аута JavaScript. Задача состоит в том, чтобы вместо этого использовать переходы CSS3.
Адам
3
Ну да. Но зачем вам вместо этого использовать «переходы CSS3», если в вашем примере вы уже используете библиотеку jQuery, которая в любом случае предоставляет много кода «меньше пиши, делай больше»? Я хотел бы отметить, что ваша версия могла бы выглядеть намного лучше, хотя и более сложной, если бы она НЕ использовала jQuery, чтобы она могла работать практически на любом веб-сайте. Я предполагаю, что сформулировал это сильно неправильно. Извините насчет этого. ;)
Kiruse
27
@ Derija93 Возможно, потому что переходы CSS3 имеют (по всем источникам, которые я могу найти) намного лучшую производительность, чем анимации jQuery. (На самом деле имеет огромное значение для моего текущего варианта использования, который привел меня сюда.)
Марк Эмери
4
@ Derija93 'Причина Анимации Javascript выполняются медленно по сравнению с переходами CSS3, братан, и с анимациями jQuery вам нужно беспокоиться о цикле анимации. Анимируйте что-нибудь по нажатию, затем быстро нажимайте и наблюдайте, как анимация повторяется. Это обрабатывается с помощью CSS3.
AlbertEngelB
2
@ Dropped.on.Caprica Сейчас он немного староват. Я уже сказал, что неправильно понял концепцию, которую он пытался продемонстрировать. В любом случае, для простых анимаций можно .stopрешить довольно сложную проблему цикла анимации. Теперь, когда вы анимируете высоту и цвет, но хотите прерывать только анимацию высоты, все становится немного сложнее ... Я понимаю вашу точку зрения.
Kiruse
43

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

Олег Васкевич
источник
Это может быть полезно, но я не могу сказать, потому что я не знаю, как использовать это без лучшего примера.
Иван Дерст
1
Вы просто передаете любой элемент DOM (например, from document.getElementById('mydiv')или $('#mydiv').get()), и функция переключается между скрытием / показом его. Если вы установили CSS-переходы, элемент будет анимирован автоматически.
Олег Васкевич
Я добавил фрагмент. Это имеет то преимущество, что хорошо работает с динамически изменяемым содержимым.
Олег Васкевич
3
-1, так как это не "использование CSS". Суть вопроса в том, чтобы найти решение без JS. Я думаю, что "правильный" ответ, это не взлом, был бы такой, хотя ...
dudewad
16
Даунвот за использование JS - серьезно? Половина ответов здесь использует JS, поэтому ваше отрицательное мнение не выглядит справедливым или необходимым. Кроме того, в этом ответе все еще используется CSS для выполнения реальной анимации, которая была главной точкой в ​​ОП. Единственное, для чего используется JS - это вычисление фактической высоты, поскольку это невозможно сделать с помощью чистого CSS (а установка, min-heightкак в ожидаемом ответе, вызывает проблемы со скоростью анимации, когда размер списка может сильно варьироваться).
Олег Васкевич
30

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

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

атп
источник
6
Вы не нашли его в других ответах здесь, потому что взаимодействие с DOM с использованием Element.scrollHeightсвойства требует JavaScript, и, как ясно указывает вопрос, они хотят сделать это без JavaScript.
TylerH
3
Есть много других частей CSS, кроме этих двух псевдоклассов, которые могут решить эту проблему, как показывают ответы с наибольшим количеством голосов на странице 1. Установка стиля в JavaScript не является «чистым CSS», так как требует, чтобы JS был установлен в первую очередь. Часто, когда человек запрашивает решение, предназначенное только для CSS, это происходит потому, что он не может внедрить какой-либо JavaScript или ему не разрешен текущий проект или роль.
TylerH
29

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

malihu
источник
12
Проблема здесь заключается в том, что для обеспечения достаточного пространства в динамической среде необходимо использовать такие нелепые максимальные высоты, как 999999px. Это, с другой стороны, сместит вашу анимацию, потому что кадры рассчитываются из этого значения. Таким образом, у вас может получиться анимация «задержки» в одном направлении и действительно быстрый конец в другом направлении (corr: сроки-функции)
Джулиан Ф. Вейнерт
29

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

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

Вивек Махарадж
источник
Отлично сделано - это верное решение проблемы, которой на самом деле не должно быть. Анимация max-height является базовой, если переход не установлен на «линейный», это также (очевидно) очень плохо для анимации содержимого CMS, где высота является переменной.
M_Willett
это умно, но мне было бы неудобно дублировать элементы DOM и контент для этого.
Андре Фигейредо
Вы можете сделать это без контейнера и повысить производительность путем анимации transform: scaleY(1), так как этот переход не удаляет пространство.
Фабиан фон Эллерс
21

Когда я публикую это, уже есть более 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>

Эндрю Мессье
источник
Хорошее сравнение @davidtaubmann, ваша ручка очень хорошо иллюстрирует различия! Я пошел translateYдальше, scaleпотому что мне не нравилось, как scaleдавал этот эффект сжатия.
Эндрю Мессье
Спасибо @ andrew-messier, я удалил комментарий, потому что есть ошибка, translateY не исключает в codepen.io/davidtaubmann/pen/zKZvGP (потому что нет ребенка, чтобы сделать движение, нужно исправить) ... но в этом В одном из них мы отлично видим сравнение ТОЛЬКО МАКС. ВЫСОТЫ и смешиваем его со шкалой (как указано в других ответах): codepen.io/davidtaubmann/pen/jrdPER . Все это мне очень помогло с методологией Target, которую я использую
DavidTaubmann
18

Итак, я думаю, что придумал очень простой ответ ... нет 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>
VIDesignz
источник
13
Это будет работать, пока высота элемента не превысит его ширину. Это основа того, как поля рассчитываются с использованием процентов: они рассчитываются на основе ширины элемента. Таким образом, если у вас есть элемент шириной 1000 пикселей, то элемент размером 1100 пикселей будет слишком большим, чтобы это решение работало, а это значит, что вам придется увеличить этот отрицательный верхний предел. По сути, это та же проблема, что и при использовании высоты или максимальной высоты.
dudewad
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.
Fiddle for LTR
Fiddle for RTL,
надеюсь, кто-то найдет это полезным в будущем.

Sijav
источник
11

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

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}
Стюарт Бадминтон
источник
@Stuart Бадминтон, можете ли вы привести рабочий пример? Я собрал это вместе, но, похоже, он нигде не работает :( jsfiddle.net/gryzzly/n5XfG
Миша Рейзлин,
5
Проблема в вашем правиле перехода. чтобы заставить его работать, нужно также применить переход к минимальной и максимальной высоте. переход: высота .5 с линейной, мин. высота .5 с линейной, макс. высота .5 с линейной
Стюарт Бадминтон
2
Вот то, что я получил позже, как вы сказали, чтобы оживить максимальную высоту: jsfiddle.net/gryzzly/n5XfG/3
Миша Рейзлин
11
Конечно, есть проблема с этим. Время, необходимое для анимации max-height, не является временем, которое требуется для перехода к автоматической высоте рамки: оно достигает высоты: сначала auto, прежде чем max-height завершит анимацию. Аналогично, при переходе к 0 переход не начинается немедленно, так как max-height начинается с высоты, которая больше, чем height: auto. Переход на максимальную высоту: 1000 пикселей делает это понятным: jsfiddle.net/n5XfG/11
stephband
Вы правы, при дальнейшем тестировании я это заметил. Я не знаю, будет ли когда-либо реализована полная высота: от 0 до высоты: авто, но использование максимальной высоты в некоторых ситуациях разрешает невозможную в противном случае ситуацию с использованием только CSS.
Стюарт Бадминтон
10

Решение Flexbox

Плюсы:

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

Минусы:

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

Он работает так, что всегда имеет flex-based: auto для элемента с содержимым, а вместо этого переходят 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 Fiddle

Ли Комсток
источник
7

Расширяя ответ @ 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/

Джей
источник
1
Я не знаю, почему это получил -1. Я на самом деле думаю, что это лучшая попытка, чем некоторые люди, добавляющие множество javascript. Это не идеальное решение, но с некоторыми изменениями оно делает хорошую работу, я нашел, что это работает для возвращаемого значения. переход: все 500 мс кубического Безье (0,000, 1,225, 0,085, 0,385); Это было основано на переходе 2s при открытии, а затем приведенном выше коде для возврата в исходное состояние. Спасибо ... Это помогло мне лучше, чем все вышеперечисленное. +1 Я использовал этот сайт, чтобы создать более безумный matthewlein.com/ceaser
gcoulby
ОК, это заняло немного больше настроек. переход: все 500 мс кубического Безье (0,000, 1,390, 0,000, 0,635); Я должен указать, что мой переход идет от 5% до 100% (но на самом деле конечное значение составляет около 28%), поэтому это зависит от проекта.
gcoulby
Безусловно, это не идеально, но это быстрое решение, если вы знаете, какова будет средняя высота.
Джейми
7

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

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

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

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

Скрипки!

JonTroncoso
источник
12
Обычно, когда кто-то спрашивает, как сделать что-то «без JavaScript», это означает, что решение должно работать в браузерах, в которых отключен JavaScript. Это не значит «без написания моих собственных сценариев». Поэтому говорить о том, что ваш плагин можно использовать без использования JavaScript, в лучшем случае вводит в заблуждение - учитывая, что это плагин JavaScript.
BoltClock
Я должен уточнить: когда я говорю, что вам не нужно использовать какой-либо специальный javascript, я имею в виду, что вам не нужно писать никакой javascript. Просто включите библиотеку JS и укажите, какие атрибуты вы хотите просмотреть в HTML. Вам не нужно использовать css с фиксированной высотой или что-нибудь придумывать. просто стиль и вперед.
JonTroncoso
«(...) на самом деле вам не нужно ничего настраивать или использовать javascript для ручной анимации (…)», так что вы используете JavaScript для развлечения
Roko C. Buljan
6

Вот способ перехода с любой начальной высоты, включая 0, на автоматический (полноразмерный и гибкий), не требующий жесткого набора кода для каждого узла или любого пользовательского кода для инициализации: https://github.com/csuwildcat / переход-авто . Я считаю, что это в основном святой Грааль для того, что вы хотите -> 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);
csuwldcat
источник
9
Хотя это гораздо более чистое и гибкое решение, чем другие, которые были предложены, я лично считаю, что JS не должно касаться этого вообще. Не сказать, что ты не прав, это просто вздох.
Mystrdat
@mystrdat, чтобы быть ясным, JS используется только для отслеживания определенных условий и добавления пары атрибутов / временных значений CSS на основе событий / условий, которые он отслеживает. Переход все еще делается в CSS. Хотя я согласен, грустно, что этот уровень настройки и удержания руки необходим, чтобы действительно удовлетворить, казалось бы, простой вариант использования! : /
csuwldcat
1
@KarolisRamanauskas Нет, это не проблема - IE поддерживает как ключевые кадры CSS, так и requestAnimationFrame. Я использовал в clipкачестве своего фиктивного триггера свойства, и по какой-то причине IE прекратил разрешать анимацию клипа. Я переключился на прозрачность, и все снова работает: codepen.io/csuwldcat/pen/FpzGa . Я обновил код в ответе, чтобы соответствовать.
csuwldcat
1
@csuwldcat Очень хорошее решение, я заметил, что контент появляется и исчезает на небольшую долю, почему это происходит? Это можно избежать?
Бето Авейга
12
Я хочу выразить это, но вместо того, чтобы отвечать на вопрос о том, как заставить его работать, вы поделились плагином, который вы написали, чтобы он работал. Нам, любопытным, оставлена ​​возможность перепроектировать ваш плагин, что не очень весело. Я хотел бы, чтобы вы обновили свой ответ, чтобы он содержал больше объяснений того, что делает ваш плагин и почему. Измените код, чтобы быть более понятным. Например, у вас есть целый раздел кода, который просто записывает статический CSS. Я бы лучше увидел CSS, чем код, который его генерирует. Вы можете пропустить скучные части, например, повторять все префиксы браузера.
gilly3
6

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

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

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

pbatey
источник
5

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

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

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

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

Чарли
источник
document.getElementById ('target_box'). getBoundingClientRect (). height должно быть лучше всего.
изменить
5

Я был в состоянии сделать это. У меня есть .child& .parentdiv. Дочерний элемент отлично вписывается в ширину / высоту родителя с 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 затем маскирует .childdiv, когда он скользит вниз.

Джош Рибаков
источник
Рабочий пример этого будет высоко ценится.
Нейротрансмиттер
5

Я опубликовал ответ с некоторым JavaScript и получил отрицательное голосование, поэтому был раздражен и попробовал снова, и взломал его только с помощью CSS!

Это решение использует несколько «техник»:

  • padding-bottom:100%«hack», где проценты определены в терминах текущей ширины элемента. Подробнее об этой технике.
  • Float Shrink-Wrap, (требующий дополнительного div, чтобы применить взломать float очистки)
  • не семантическое использование https://caniuse.com/#feat=css-writing-mode и некоторых преобразований для его отмены (это позволяет использовать хак с отступами выше в вертикальном контексте)

В результате мы получаем эффективный переход с использованием только CSS и единой функции перехода для плавного достижения перехода; Святой Грааль!

Конечно, есть и обратная сторона! Я не могу понять, как контролировать ширину, на которой содержимое обрезается ( overflow:hidden); из-за взлома padding-bottom, ширина и высота тесно связаны между собой. Хотя может быть способ, так что вернемся к нему.

https://jsfiddle.net/EoghanM/n1rp3zb4/28/

body {
  padding: 1em;
}

.trigger {
  font-weight: bold;
}

/* .expander is there for float clearing purposes only */
.expander::after {
  content: '';
  display: table;
  clear: both;
}

.outer {
  float: left; /* purpose: shrink to fit content */
  border: 1px solid green;
  overflow: hidden;
}

.inner {
  transition: padding-bottom 0.3s ease-in-out;  /* or whatever crazy transition function you can come up with! */
  padding-bottom: 0%;  /* percentage padding is defined in terms of width. The width at this level is equal to the height of the content */
  height: 0;

  /* unfortunately, change of writing mode has other bad effects like orientation of cursor */
  writing-mode: vertical-rl;
  cursor: default; /* don't want the vertical-text (sideways I-beam) */
  transform: rotate(-90deg) translateX(-100%);  /* undo writing mode */
  transform-origin: 0 0;
  margin: 0;  /* left/right margins here will add to height */
}

.inner > div { white-space: nowrap; }

.expander:hover .inner,  /* to keep open when expanded */
.trigger:hover+.expander .inner {
  padding-bottom: 100%;
}
<div class="trigger">HoverMe</div>
<div class="expander">
  <div class="outer">
    <div class="inner">
      <div>First Item</div>
      <div>Content</div>
      <div>Content</div>
      <div>Content</div>
      <div>Long Content can't be wider than outer height unfortunately</div>
      <div>Last Item</div>
    </div>
  </div>
</div>
<div>
  after content</div>
</div>

EoghanM
источник
Другим недостатком этого является то, что вы не можете переместить курсор из div «hoverme» в список элементов, чтобы взаимодействовать с ними (якобы причина для запроса OP), поэтому он полезен только в качестве функции всплывающей подсказки, а не скажем, меню с вложенными подменю.
TylerH
Это чисто следствие того, как вопрос был сформулирован и не имеет отношения к технике. Вы можете изменить триггер на « input[type="checkbox"]:checkedвместо», :hoverесли хотите (то есть вы не хотите использовать JavaScript для добавления классов)
EoghanM
Я имею в виду, независимо от того, как сформулирован вопрос, если реализация решения настолько ограничена, его, вероятно, следует упомянуть в ответе этого решения (или, желательно, учесть ). Вы упоминаете, что это решение является «святым Граалем», но переходный div не может даже зависнуть ... мне не кажется таким окончательным решением.
TylerH
Привет @ TylerH, извиняюсь, я пропустил тот факт, что триггер в исходном вопросе окружает расширенный список, поэтому список должен оставаться открытым, когда наведен курсор. Я обновил свой ответ, чтобы отразить это. Как я уже упоминал, то, как он запускается, не совсем уместно, так как я представляю новую технику, которая ранее не считалась возможной только в CSS (я искал решение в течение нескольких лет).
EoghanM
4

Вот решение, которое я только что использовал в сочетании с 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'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 }
HandiworkNYC.com
источник
это не отображается должным образом с новейшей версией jquery
oliverbachmann
4

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

mindfullsilence
источник
3

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

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

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

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

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

work.stella84
источник
3

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

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

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

В следующем коде используется переход на поле margin-bottom от -150px до 0px. Это само по себе работает нормально, если элемент содержимого не превышает 150 пикселей. Кроме того, он использует переход на max-height для среднего элемента от 0px до 100%. Это, наконец, скрывает средний элемент, если элемент содержимого выше 150px. Для максимальной высоты переход используется только для задержки его применения на секунду при закрытии, а не для получения плавного визуального эффекта (и, следовательно, он может работать от 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>

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

Для получения дополнительной информации см. Мой пост в блоге http://www.taccgl.org/blog/css_transition_display.html#combined_height

Хельмут Эммельманн
источник
3

Вы можете сделать это, создав обратную анимацию (свернуть) с помощью clip-path.

#child0 {
    display: none;
}
#parent0:hover #child0 {
    display: block;
    animation: height-animation;
    animation-duration: 200ms;
    animation-timing-function: linear;
    animation-fill-mode: backwards;
    animation-iteration-count: 1;
    animation-delay: 200ms;
}
@keyframes height-animation {
    0% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 0%, 0% 0%);
    }
    100% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 100%, 0% 100%);
    }
}
<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>

Андрий
источник
2

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

.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 в настоящее время невозможно, но преобразование содержимого внутри, следовательно, переход размера шрифта.

  • Обратите внимание - в коде есть IS javascript, но его единственная цель - добавлять / удалять классы CSS по клику для аккордеона. Это можно сделать с помощью скрытых переключателей, но я не сосредоточился на этом, только на изменении высоты.
Майк С.
источник
1
Эффективно дублирует этот ответ , но пропускает эффект исчезновения непрозрачности.
SeldomNeedy
Согласовано. Лучший подход.
Майк С.