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

1670

Я пытаюсь сделать слайд <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>
  • 0
    Я считаю, что решение height:auto/max-height будет работать только в том случае, если вы расширяете область больше, чем height вы хотите ограничить. Если у вас max-height 300px , но выпадающий список со списком, который может вернуть 50px , тогда max-height не поможет, 50px является переменной величиной в зависимости от количества элементов, вы можете оказаться в невозможной ситуации, когда я не могу исправить это, потому что height не фиксирована, height:auto было решением, но я не могу использовать переходы с этим.
  • 44
    OP пытается найти решение css, а не js, иначе они могут просто использовать переполнение и анимировать
Показать ещё 2 комментария
Теги:
css-transitions

47 ответов

2362
Лучший ответ

Используйте 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>
  • 269
    это прекрасно работает! за исключением того, что есть задержка, когда он запускается, потому что он начинается для максимальной высоты, которая изначально очень высока ... хм, я думаю, что это несколько раздражает
  • 160
    +1 Отличное решение! Скорость перехода вычисляется как время, указанное вами для перехода к значению max-height ... но поскольку высота будет меньше, чем max-height, переход к фактической высоте будет происходить быстрее (часто значительно), чем Время указано.
Показать ещё 28 комментариев
245

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

  • 6
    Я одобряю этот ответ, потому что он хорошо работает в браузерах с поддержкой css3-transition, но следует отметить, что это не будет работать вообще в IE <9 , и не будет анимированным (он просто будет прыгать) в IE <10
  • 164
    Этот метод только частично достигает желаемого эффекта, но фактически не удаляет пространство. Преобразованная коробка действует как относительно позиционированный элемент - пространство занимает независимо от того, как оно масштабируется. Проверьте этот jsFiddle, который берет ваш первый и просто добавляет поддельный текст внизу. Обратите внимание, что текст под ним не перемещается вверх, когда высота поля масштабируется до нуля.
Показать ещё 10 комментариев
177

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

  • 11
    Обычно существует несколько способов решения проблемы, и не все из них являются подходящими или возможными. Я не знаю, почему @JedidiahHurt и Ryan Ore пытаются ограничить возможные ответы на сайте вопросов и ответов. Особенно учитывая, что этот ответ был здесь первым. Вдвойне, так как принятый ответ - это обходной путь.
  • 5
    Ответ @jake не является ни элегантным, ни правильным. Связанный ответ здесь намного лучше. Он работает правильно и обрабатывает все случаи размера - ни один не может быть сказано о принятом ответе.
Показать ещё 5 комментариев
101

Решение, которое я всегда использовал, состояло в том, чтобы сначала постепенно затухать, а затем уменьшать 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>
  • 0
    Работал аккуратно для меня. Не совсем как jQuery slideUp / Down. Вы можете увидеть разницу только со слабыми процессорами, такими как старые компьютеры или мобильные устройства, и открыв и закрыв многие из них одновременно.
  • 2
    Если у вас есть кнопки или любые другие нетекстовые элементы, вы получите нежелательные пробелы, не зависая.
Показать ещё 3 комментария
69

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

  • 10
    Так как это зависит от javascript, вы также можете легко добавить measureWrapper, используя также javascript!
  • 0
    Quickredfox, мне нравится твое предложение. Я смог использовать ваше предложение в сочетании с методом replaceChild и следующей техникой, чтобы добавить div-оболочку без нарушения каких-либо существующих ссылок на элементы DOM: stackoverflow.com/questions/6938248/… . Кроме того, мне не понравилось, как я не мог открыть закрывающий div в среднем потоке, поэтому я добавил логическое свойство isOpening к объекту DOM, а затем использовал его, чтобы узнать, открывался ли div или закрывался. Это дало мне намного больше контроля над модулем аккордеона, который я построил. Во всяком случае, еще раз спасибо. Отличный ответ!
Показать ещё 6 комментариев
64

Я знаю, что это тридцать-точный ответ на этот вопрос, но я думаю, что это того стоит, так что и здесь. Это 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>

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

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

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

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

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

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

Изображение 4867

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

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

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

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

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

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

Вторая проблема - причина, по которой мы фактически не используем min-height для минимального перехода высоты. Вместо этого существует псевдоэлемент ::after в контейнере с height, который переходит от 50px к нулю. Это имеет тот же эффект, что и 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, что делает его довольно бессмысленным упражнением.

  • 15
    Я хотел бы, чтобы вы могли сократить (упростить) свое решение или хотя бы пример кода - похоже, что 90% примера кода не имеет отношения к вашему ответу.
47

Мое обходное решение - переход 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>
  • 0
    Smarty! Мне нравится решение max-height only! Контент, который я оживляю, не так уж и гибок :)
  • 0
    Довольно легко победить ... jQuery на самом деле предоставляет .slideUp , .slideDown и .slideToggle , которые не делают высоту статичной. Попробуй это. По сути, это всего лишь одна строка, которая делает то же самое и расширяет ее до точки, где она анимируется, даже когда вы расширяете контент, не должно быть слишком сложной задачей. Так как вы уже используете jQuery ...
Показать ещё 8 комментариев
45

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

  • 3
    Я думаю, что это лучший ответ. Эта техника может распространяться и на детей. В моем случае я смог объединить это с явными переходами по высоте для некоторого раскрываемого содержимого, и общий эффект гораздо более успешен, чем обход максимальной высоты, что хорошо для раскрытия, но вводит неловкий момент задержка на спрятаться Раньше я бы вообще не оживлял, чем вводил бы бессмысленную задержку, из-за которой мое приложение казалось бы не отвечающим. Я удивлен, что многие люди считают это приемлемым.
  • 13
    За исключением того, что здесь вы вообще не анимируете высоту. Вы анимируете заполнение ... оно может просто исчезнуть, потому что оно может анимироваться из текущего состояния до 0, но если вы внимательно посмотрите, когда оно расширяется, оно откроется с текстом, а затем заполнение только оживит .. потому что это не не знаю, как анимировать от 0 до авто .... ему нужен числовой диапазон ... вот как работает анимация движения.
Показать ещё 3 комментария
34

Принятый ответ работает в большинстве случаев, но он не очень хорошо работает, когда ваш 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>
  • 0
    Это может быть полезно, но я не могу сказать, потому что я не знаю, как использовать это без лучшего примера.
  • 1
    Вы просто передаете любой элемент DOM (например, из document.getElementById('mydiv') или $('#mydiv').get() ), и функция переключается между его скрытием / показом. Если вы установили CSS-переходы, элемент будет анимирован автоматически.
Показать ещё 4 комментария
26

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

  • 8
    Проблема здесь заключается в том, что для обеспечения достаточного пространства в динамической среде необходимо использовать смешные максимальные высоты, например 999999px . Это, с другой стороны, сместит вашу анимацию, потому что кадры рассчитываются по этому значению. Таким образом, у вас может получиться анимация «задержки» в одном направлении и действительно быстрый конец в другом направлении (corr: timer-functions)
24

Было мало упоминания о свойстве 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 (которые в настоящее время получают некоторую особую обработку).

  • 5
    Вы не нашли его в других ответах здесь, потому что взаимодействие с DOM с использованием свойства Element.scrollHeight требует JavaScript, и, как ясно указывает вопрос, они хотят сделать это без JavaScript.
  • 1
    Правильно. Когда что-то слишком хорошо, чтобы быть правдой, это обычно так. Я также нашел некоторые упоминания о scrollHeight , выполнив более тщательный поиск в этот раз, хотя код, использующий его, кажется довольно запутанным и определенно содержит больше JavaScript, чем необходимо сегодня. В любом случае, я полагаю, что вы правы с no-JavaScript, но без Javascript вы ограничены :active и :focus и, возможно, парой других псевдоклассов, поэтому мне интересно, что именно означает «No JavaScript». Как в "чистой CSS-анимации"? Потому что установка стиля в JavaScript все еще является чистой и разлагаемой CSS-анимацией.
Показать ещё 4 комментария
24

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

Нет 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>
  • 6
    Хорошее решение, но очень больно видеть здесь дублирование кода ...
  • 0
    Отлично сделано - это верное решение проблемы, которой на самом деле не должно быть. Анимация max-height является базовой, если переход не установлен на «линейный», это также (очевидно) очень плохо для анимации содержимого CMS, где высота является переменной.
20

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

Хорошо, поэтому я думаю, что придумал супер простой ответ... 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>
  • 11
    Это будет работать до тех пор, пока высота элемента не превысит его ширину. Это основа того, как поля рассчитываются с использованием процентов: они рассчитываются на основе ширины элемента. Поэтому, если у вас есть элемент шириной 1000 пикселей, то элемент размером 1100 пикселей будет слишком большим, чтобы это решение работало, а это означает, что вам придется увеличить этот отрицательный верхний предел. По сути, это та же проблема, что и при использовании высоты или максимальной высоты.
13

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

12

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

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}
  • 0
    @Stuart Бадминтон, можете ли вы привести рабочий пример? Я собрал это вместе, но, кажется, нигде не работает :( jsfiddle.net/gryzzly/n5XfG
  • 5
    Проблема в вашем правиле перехода. чтобы заставить его работать, нужно также применить переход к минимальной и максимальной высоте. переход: высота .5 с линейной, мин. высота. 5 с линейной, макс. высота. 5 с линейной
Показать ещё 5 комментариев
10

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

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

скрипки!

  • 7
    Обычно, когда кто-то спрашивает, как сделать что-то «без JavaScript», это означает, что решение должно работать в браузерах, в которых отключен JavaScript. Это не значит «без написания моих собственных сценариев». Поэтому говорить о том, что ваш плагин можно использовать без использования JavaScript, в лучшем случае вводит в заблуждение - учитывая, что это плагин JavaScript.
  • 0
    Я должен уточнить: когда я говорю, что вам не нужно использовать какой-либо специальный javascript, я имею в виду, что вам не нужно писать никакой javascript. Просто включите библиотеку JS и укажите, какие атрибуты вы хотите просмотреть в HTML. Вам не нужно использовать css с фиксированной высотой или что-нибудь придумывать. просто стиль и вперед.
9

Решение 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>

JS Fiddle

8

Здесь вы можете перейти от любой начальной высоты, включая 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);
  • 2
    Не уверен, почему я получил -1 на этом, это эмпирически лучшее решение, которое делает именно то, что запрашивал OP, без жестко запрограммированных значений или какого-либо уродства максимальной высоты.
  • 9
    Хотя это гораздо более чистое и гибкое решение, чем другие, которые были предложены, я лично считаю, что JS не должно касаться этого вообще. Не сказать, что ты не прав, это просто вздох.
Показать ещё 8 комментариев
7

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

7

Ответ Джейка для анимации 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/

5

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

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

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

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

  • 0
    document.getElementById ('target_box'). getBoundingClientRect (). height должно быть лучше всего.
  • 0
    извините, но только для IE
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

4

Я смог это сделать. У меня есть 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, когда он скользит вниз.

  • 0
    Рабочий пример этого будет высоко оценен.
4

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

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

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

например:

.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
  • 0
    ОК, это заняло немного больше настроек. переход: все 500 мс кубического Безье (0,000, 1,390, 0,000, 0,635); Я должен указать, что мой переход идет от 5% до 100% (но на самом деле конечное значение составляет около 28%), поэтому это зависит от проекта.
Показать ещё 1 комментарий
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 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 }
  • 0
    это не отображается должным образом с последней версией JQuery
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, который сначала отображает контент размером до 200 пикселей, а при наведении его размер становится как минимум таким же высоким, как и весь контент div. Div не становится 3000px, но 3000px является пределом, который я навязываю. Убедитесь, что у вас есть переход на не-зависание, иначе вы можете получить какой-то странный рендеринг. Таким образом: hover наследуется от не-зависания.

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

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

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

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

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

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

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

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

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

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

Подробнее см. в сообщении моего блога http://www.taccgl.org/blog/css_transition_display.html#combined_height

2

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

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

2

Установите высоту в auto и перейдите на максимальную высоту.

Протестировано на Chrome v17

div {
  position: absolute;
  width:100%;
  bottom:0px;
  left:0px;

  background:#333;
  color: #FFF;

  max-height:100%; /**/
  height:auto; /**/

  -webkit-transition: all 0.2s ease-in-out;
  -moz-transition: all 0.2s ease-in-out;
  -o-transition: all 0.2s ease-in-out;
  -ms-transition: all 0.2s ease-in-out;
  transition: all 0.2s ease-in-out;
}

.close {
  max-height:0%; /**/
}
  • 0
    Это не сработало на последней Chrome Canary для меня
1

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

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

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

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

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

Это регулярная проблема, которую я решил как это

http://jsfiddle.net/ipeshev/d1dfr0jz/

Попробуйте установить задержку закрытого состояния на некоторое отрицательное число и немного сыграйте со значением. Вы увидите разницу. Его можно заставить лгать человеческим глазом;).

Он работает в основных браузерах, но достаточно хорош для меня. Это странно, но дать некоторые результаты.

.expandable {
    max-height: 0px;
    overflow: hidden;
    transition: all 1s linear -0.8s;
}

button:hover ~ .expandable {
    max-height: 9000px;
    transition: all 1s ease-in-out;
}
  • 0
    в jsFiddle ничего не видно, и поэтому ничего не доступно
  • 0
    Кроме того, как только у меня есть элемент, который 9001 пикселей, это решение ломается :)
Показать ещё 1 комментарий
0

Как насчет высоты, вы используете что-то вроде ниже

#child0 {
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s, opacity 0.5s linear;
  position: absolute;
} 

#parent0:hover #child0 {
  visibility: visible;
  opacity: 1;
  position: relative;
}

Хорошо работает. Пожалуйста, добавьте префиксы. Надеюсь, это поможет кому-то.

PS: если вам все еще нужна высота 0 для высоты чего-то черной магии, вы можете добавить height: 0; в #child0, а затем добавить height: inherit в #parent0:hover #child0. Одновременно вы можете добавить переход для высоты отдельно или только вы все.

  • 0
    Это отвечает на другой вопрос. Пожалуйста, ответьте на вопрос
  • 0
    @SoldeplataSaketos это ответ на вопрос, который я думаю. Все, что я предлагаю, - это другой подход, потому что я столкнулся с подобной ситуацией, упомянутой в вопросе, и успешно смог ее решить и повторно использовать во многих проектах.
Показать ещё 1 комментарий
0

Отметьте мой пост по поводу некоторого смежного вопроса.

В принципе, начинайте с height: 0px; и переходите к точной высоте, вычисленной по JavaScript.

function setInfoHeight() {
  $(window).on('load resize', function() {
    $('.info').each(function () {
      var current = $(this);
      var closed = $(this).height() == 0;
      current.show().height('auto').attr('h', current.height() );
      current.height(closed ? '0' : current.height());
    });
  });

Всякий раз, когда страница загружается/изменяется, элемент с классом info будет обновлен атрибут h. Затем кнопка запускает style="height: __", чтобы установить ее на ранее установленное значение h.

function moreInformation() {
  $('.icon-container').click(function() {
    var info = $(this).closest('.dish-header').next('.info'); // Just the one info
    var icon = $(this).children('.info-btn'); // Select the logo

    // Stop any ongoing animation loops. Without this, you could click button 10
    // times real fast, and watch an animation of the info showing and closing
    // for a few seconds after
    icon.stop();
    info.stop();

    // Flip icon and hide/show info
    icon.toggleClass('flip');

    // Metnod 1, animation handled by JS
    // info.slideToggle('slow');

    // Method 2, animation handled by CSS, use with setInfoheight function
    info.toggleClass('active').height(icon.is('.flip') ? info.attr('h') : '0');

  });
};

Здесь стиль для класса info.

.info {
  padding: 0 1em;
  line-height: 1.5em;
  display: inline-block;
  overflow: hidden;
  height: 0px;
  transition: height 0.6s, padding 0.6s;
  &.active {
    border-bottom: $thin-line;
    padding: 1em;
  }
}

Стиль может не поддерживаться кросс-браузер. Вот живой пример для этого кода:

CodePen

0

МАЛЕНЬКИЕ РЕШЕНИЯ JASTASCRIPT + SCSS

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

  • что мы действительно хотим, это изменение высоты

  • Высота - это сумма всех элементов списка внутри подменю

  • Обычно мы знаем высоту элемента списка, так как мы его стиль

Итак, мое решение применимо к "нормальным" подменю, где имена элементов имеют только 1 строку. Во всяком случае, с чуть большим количеством js можно было бы разместить более 1 строки.

В основном, я просто подсчитываю элементы подменю и соответствующим образом применяю определенные классы. Затем передайте мяч (s) css. Итак, например:

var main_menu = $('.main-menu');
var submenus = $('.main-menu').find('.submenu');
submenus.each(function(index,item){
   var i = $(item);
   i.addClass('has-' + i.find('li').length + '-children');
});

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

<ul class="submenu has-3-children">
   <li></li>
   <li></li>
   <li></li>
</ul>

И наш css вот так:

.submenu{
   //your styles [...]
   height:0;
   overflow:hidden;
   transition: all 200ms ease-in-out; //assume Autoprefixer is used
}

Мы также будем иметь некоторые scss-переменные, подобные этим (произвольный пример):

$sub_item_height:30px;
$sub_item_border:2px;

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

//use a number of children reasonably high so it won't be overcomed by real buttons
.main-menu .opened .submenu{
   &.has-1-children{ height:   $sub_item_height*1  + $sub_item_border*1;  }
   &.has-2-children{ height:   $sub_item_height*2  + $sub_item_border*2;  }
   &.has-3-children{ height:   $sub_item_height*3  + $sub_item_border*3;  }
   //and so on....
}

Или, чтобы сократить:

.main-menu .opened .submenu{
   @for $i from 1 through 12{//12 is totally arbitrary
      &.has-#{$i}-children { height: $menu_item_height * $i + $menu_item_border * $i; }
   }
}

В большинстве случаев это будет выполнять эту работу. Надеюсь, это поможет!

0

Я встретил эту проблему и нашел способ обхода.

Сначала я попытался использовать max-height. Но есть две проблемы:

  • Я не уверен, что такое max-height, так как я расширяю текстовый блок неизвестной длины.
  • Если я установил max-height слишком большой, происходит большая задержка при свертывании.

Затем мое обходное решение:

function toggleBlock(e) {
    var target = goog.dom.getNextElementSibling(e.target);
    if (target.style.height && target.style.height != "0px") { //collapsing
        goog.style.setHeight(target, target.clientHeight);
        setTimeout(function(){
            target.style.height = "0px";
        }, 100);
    } else { //expanding
        target.style.height = "auto";
        //get the actual height
        var height = target.clientHeight;
        target.style.height = "0px";
        setTimeout(function(){
            goog.style.setHeight(target, height);
        }, 100);
        setTimeout(function(){
            //Set this because I have expanding blocks inside expanding blocks
            target.style.height="auto";
        }, 600); //time is set 100 + transition-duration
    }
}

Scss:

div.block {
    height: 0px;
    overflow: hidden;
    @include transition-property(height);
    @include transition-duration(0.5s);
}
0

Я рассматривал эту проблему некоторое время сегодня и наткнулся на это решение:

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

$(obj).children().each(function(index, element) {
   InnerHeight += $(this).height();
});

для анимации до полного размера:

$(obj).removeClass('collapsed').css('max-height', InnerHeight);

для анимации меньшего размера:

$(obj).removeClass('collapsed').css('max-height', MySmallerHeight);

использовать переход CSS3: max-height;

Таким образом, вы избегаете глянцевой анимации от дороги до большой высоты. И вы не рискуете обрезать свой контент.

0

Я получил эту работу, установив max-height на none, получив высоту, переустановив максимальную высоту до вычисленной высоты. Работает для меня префект. Я получил это, работая для меню гармоник, с <h5> как toggler, расширяющий <div> внутри <div>.

JS:

$('h5').click(function(e) {
  $(this).parent('div').addClass('temp_expanded');
  var getheight = ($(this).parent('div').find('div').height());
  $(this).parent('div').removeClass('temp_expanded');
  $(this).parent('div').find('div').css('max-height', getheight);
});

LESS:

div {
> div {
    max-height: 0px;
    overflow: hidden;
    .transition(all 0.3s ease-in-out);
}

&.temp_expanded {
    > div {
        max-height: none;
    }
}
  • 0
    Да, и меньше для поставщика префикса переходов.
-1

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

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

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

При открытии я добавляю обработчик события transitionend который будет запускаться только один раз, затем удаляю встроенный стиль, устанавливая его обратно в height: auto;

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

const showHideElement = (element, open) => {
  element.style.height = [].reduce.call(element.children, (totalHeight, child) => (
    totalHeight + child.clientHeight
  ), 0) + 'px';

  element.classList.toggle('open', open);

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

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>

и более сложный пример с подпунктами...
https://codepen.io/ninjabonsai/pen/GzYyVe

-1

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

var unrolled = false;

$( "#unroll" ).click(function() {
  if(!unrolled){
     $('.block-of-text').css("max-height", $('.whole-content').height() + "px");
     unrolled=true;
  }
  else{
     $('.block-of-text').removeAttr("style");
     unrolled=false;
  }
 
});
.block-of-text{
  width:200px;
  max-height:150px;
  padding:25px;
  background:rgba(0,0,255,0.6);
  transition:0.4s;
  color:white;
  display:inline-block;
  overflow:hidden;
}
#unroll{
  position:absolute;
  left:280px;
  background:transparent;
  color:blue;
  border:2px solid blue;
  transition:0.4s;
  top:20px;
}
#unroll:hover{
  background:blue;
  color:white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="block-of-text">
  <div class="whole-content">
    YOU CAN PLACE HERE AS MUCH TEXT AS YOU WANT <br>
    Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Suspendisse enim turpis, dictum sed, iaculis a,<br>
    Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Suspendisse enim turpis, dictum sed, iaculis a,<br>
    Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Suspendisse enim turpis, dictum sed, iaculis a,<br>
    Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Suspendisse enim turpis, dictum sed, iaculis a,<br>
    <br><br><br><br>
    Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Suspendisse enim turpis, dictum sed, iaculis a,<br>
    Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. END OF CONTENT,<br>
  </div>
</div>

<button id="unroll">
   Unroll block
</button>
-2

Это то, что работает для меня:

  .hide{
    max-height: 0px;
    overflow: hidden;
    transition:max-height .5s ease-in-out;
  }

  .show{
    max-height: 150px; // adjust as needed
    transition: max-height .5s ease-in-out;
  }

вам нужно поместить их во все ваши дочерние компоненты и переключать их с помощью состояния jQuery или React, здесь мой случай (с next.js и styled-components): https://codesandbox.io/s/ol3kl56q9q

-2

В этих решениях используется javascript, но это очень тривиально, и он работает достаточно хорошо.

HTML:

<button>Toggle</button>
<div class="container collapsed">
  <div class="content">
    <div>Lorem</div>
    <div>Ipsum</div>
    <div>Dolor</div>
    <div>Sit</div>
    <div>Amet</div>
  </div>
</div>

CSS

.container
{
  overflow: hidden;
  transition: 0.5s ease;
}

.container.collapsed
{
  height: 0 !important;
}

JavaScript:

$("button").click(
    function ()
    {
        var height = $(".content").height();
        $(".container").css({height: height});
        $(".container").toggleClass("collapsed");
    });

http://jsfiddle.net/r109uz7m/ (включает обходной путь к недостатку, описанному ниже):

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

  • 0
    Что вам не хватает, так это вопрос с тегом CSS, а в заголовке написано «использование CSS».
  • 0
    Ну, что вы упускаете, так это то, что без javascript невозможно решить эту проблему. Большинство предлагаемых здесь ответов, особенно те, которые входят в число самых популярных, используют javascript, но гораздо более сложным способом, чем предложенное здесь решение. Я надеюсь, что вы отклонили все остальные ответы, которые также используют javascript.
Показать ещё 10 комментариев
-2

Пример короткого кода:

.slider ul {
  overflow: hidden;
  -webkit-transition: max-height 3.3s ease;
}

.slider.hide ul {
  max-height: 0px;
}

.slider.show ul {
  max-height: 1000px;
}
-3

Если количество "li" > 30 штук, то высота обертки будет > 500px. Мой ответ:

ul{width:100%}
li{height:0;overflow:hidden;background:#dedede;transition:.2s.4s linear}
ul:hover li{height:20px}
<ul>Hover me
<li>Juice</li>
<li>Tea</li>
<li>Milk</li>
<li>Coffee</li>
</ul>
-3

Я также сделал это с jQuery. В моем случае я хотел увидеть немного другого меню (10 пикселей). Таким образом, это работает без Javascript (но также и перехода).

#menu li ul {
        list-style: none;
        height: 10px;
        overflow: hidden;
        margin: 0;
        padding: 0;
    }
        #menu li:hover ul {
            height: 100%;
        }

Это мой js:

//Save the height set in css (10px)
var csshoehe = $("ul li ul").height();

// Open all the menus
$("ul li ul").css("height", "100%");

//Save each height in data-attribute
//then shrink it down again
$.each($("ul li ul"), function(){
    var hoehe = $(this).height();
    $(this).data("hoehe", hoehe);
    $(this).css("height", csshoehe);
});

$("ul li").hover(
    function(){
        var orig = $(this).children("ul").data("hoehe");
        $(this).children("ul").stop(true,false).delay(150).animate({"height": orig});
},  function(){
        $(this).children("ul").stop(true,false).delay(400).animate({"height": csshoehe});
});

Надеюсь, это поможет кому-то:)

-4

это то, что я использовал.

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

Проверьте это.

                            <!doctype html>
                            <html>

                            <head>
                                <style>
                                    /* OVERFLOW HIDDEN */
                                    .overflowHidden{
                                        overflow: hidden;
                                    }

                                    /* HEIGHT */
                                    .transitionHeight{
                                        -webkit-transition: max-height 250ms ease-in-out;
                                        -moz-transition: max-height 250ms ease-in-out;
                                        -o-transition: max-height 250ms ease-in-out;
                                        -ms-transition: max-height 250ms ease-in-out;
                                        transition: max-height 250ms ease-in-out;
                                    }
                                    .heightAnimOff{
                                        height: auto;
                                        max-height: 0px;
                                    }
                                    .heightAnimOn{
                                        height: auto;
                                        max-height: 20000px;
                                    }

                                </style>
                                <script src="jquery_1.8.3.min.js" type="text/javascript"></script>
                                <script type="text/javascript">
                                    (function($){
                                            $.toggleAnimHeight = function(alvo, velha, nova){
                                                if ( $(alvo).attr("data-maxHeight") != null ){
                                                }else{
                                                    var totalH = 0;
                                                    $(alvo).children().each(function(){
                                                        totalH += $(this).height();
                                                    });
                                                    $(alvo).attr("data-maxHeight", totalH)
                                                    $("head").append('<style> .'+nova+'{ max-height: '+totalH+'px; } </style>');
                                                }           
                                                if ( $(alvo).attr("class").indexOf(nova) == -1 ){
                                                    $(alvo).removeClass(velha);
                                                    $(alvo).addClass(nova);
                                                }else {
                                                    $(alvo).removeClass(nova);
                                                    $(alvo).addClass(velha);
                                                }
                                            }
                                    }(jQuery));
                                </script>
                            </head>

                            <body>
                                <div class="animContainer">
                                    <button onmousedown="$.toggleAnimHeight( $('#target1'), 'heightAnimOff', 'heightAnimOn' );">Anim Toggle</button>
                                    <div id="target1" class="overflowHidden heightAnimOff transitionHeight">
                                        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id pretium enim, quis faucibus urna. Phasellus blandit nisl eget quam mollis vulputate. Sed pulvinar eros vitae neque volutpat, vitae suscipit urna viverra. Etiam rhoncus purus vitae tortor pulvinar, sed vulputate arcu convallis. Sed porta, mi consectetur convallis semper, odio mauris iaculis purus, non tempor purus augue pharetra lorem. Integer dictum lacus arcu. Vivamus metus lorem, fermentum ac egestas ac, ornare non neque. Aenean ullamcorper adipiscing ante, et mollis orci feugiat et.</p>

                                        <p>Praesent pretium sit amet eros et lacinia. Etiam nec neque ullamcorper, sagittis quam vitae, dictum ipsum. Sed volutpat lorem libero, nec commodo magna posuere rutrum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque id erat odio. Sed faucibus sem eu tortor laoreet pulvinar. Praesent pharetra risus eget metus vulputate, eget condimentum leo consequat. Praesent consequat rutrum convallis.</p>

                                        <p>Aenean euismod metus quis libero commodo, tristique cursus odio vestibulum. Donec quis lobortis arcu, eu luctus diam. In eget nisi non mauris commodo elementum. Sed gravida leo consequat, tempus orci eu, facilisis ipsum. Cras interdum sed odio vel tincidunt. Morbi arcu ipsum, ultricies dictum enim quis, varius dignissim massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec semper, magna eu aliquam luctus, leo purus accumsan massa, at auctor dui dolor eu augue. Maecenas ultrices faucibus ante non mattis.</p>

                                        <p>Pellentesque ut est tortor. Quisque adipiscing ac nisi vel interdum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut facilisis ante sollicitudin vehicula ornare. Quisque sagittis diam nibh, ac imperdiet nibh pulvinar eu. Integer at ipsum a purus tristique porttitor vitae in ante. Sed arcu neque, lacinia eu dolor nec, pellentesque interdum tortor. Morbi ornare aliquet aliquam. Aenean egestas, erat vel tempus mollis, est eros iaculis enim, quis fringilla purus tortor sollicitudin erat. Donec ultrices elit metus, sed iaculis mi dignissim vulputate. Donec adipiscing imperdiet porttitor. Sed ac lacus adipiscing, sagittis sem quis, tincidunt metus. Curabitur vitae augue a dolor scelerisque lobortis ut a nisi.</p>

                                        <p>Quisque sollicitudin diam sit amet dui sollicitudin, ac egestas turpis imperdiet. Nullam id dui at lectus ultrices aliquam. Nam non luctus tortor, vitae elementum elit. Nullam id bibendum orci. Aliquam hendrerit nisi vitae tortor mollis, nec aliquam risus malesuada. In scelerisque nisl arcu, sit amet tincidunt libero consequat pharetra. Quisque aliquam consectetur purus nec sollicitudin. Pellentesque consectetur eleifend tortor in blandit. Pellentesque euismod justo sed lectus congue, ut malesuada diam rhoncus. Nulla id tempor odio. Nulla facilisi. Phasellus lacinia neque in nisi congue aliquet. Aliquam malesuada accumsan mauris eget mattis. Maecenas pellentesque, sem sed ultricies ullamcorper, massa enim consectetur magna, eget sagittis lorem leo vel arcu. Cras ultrices nunc id risus commodo laoreet. Proin nisl nulla, elementum ac libero sed, aliquam mollis massa.</p>
                                    </div>
                                </div>
                            </body>

                            </html>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню