Я пытаюсь заставить <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>
2500
Hailwood 18 Авг 2010 в 06:50
Я считаю, что решение height:auto/max-height будет работать, только если вы расширяете область больше, чем height, которую вы хотите ограничить. Если у вас есть max-height из 300px, но раскрывающийся список со списком, который может возвращать 50px, то max-height вам не поможет, 50px является переменной в зависимости от количества элементов, вы можете попасть в невозможную ситуацию, когда я не могу это исправить, потому что height не исправлен, height:auto был решением, но я не могу использовать переходы с этим .
 – 
Christopher Thomas
9 Май 2012 в 16:31
71
OP пытается найти решение css, а не js, иначе они могли бы просто использовать переполнение и анимировать
 – 
Toni Leigh
16 Апр 2015 в 19:39
5
@VIDesignz: Но внутренний div -100% margin-top получает ширину обертки div, не высоту. Таким образом, это решение имеет ту же проблему, что и макс-высота решения. Более того, когда ширина меньше, чем высота содержимого, не весь контент скрывается -100% margin-top. Так что это неправильное решение.
 – 
GregTom
27 Дек 2015 в 11:23
3
См. Обсуждение github.com/w3c/csswg-drafts/issues/626 вокруг спецификации и реализации правильного решения
 – 
Ben Creasy
20 Июл 2017 в 05:10
Вопрос в высоте, а не в ширине. Все ответы про рост. Пожалуйста, не меняйте заголовок вопроса, чтобы он не относился к теме.
 – 
TylerH
25 Окт 2021 в 02:19

32 ответа

Лучший ответ

Используйте в переходе 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>
3243
jlouzado 16 Окт 2019 в 22:21
404
Это отлично работает! за исключением того, что при запуске есть задержка, потому что он начинается с максимальной высоты, которая изначально очень высока ... хмм, я думаю, что это несколько раздражает
 – 
vsync
5 Дек 2011 в 20:03
197
+1 Отличное решение! Скорость перехода рассчитывается как время, которое вы указываете для перехода к значению max-height ... но поскольку высота будет меньше max-height, переход к фактической высоте будет происходить быстрее (часто значительно), чем время указано.
 – 
kingjeffrey
3 Мар 2012 в 08:15
72
Обратите внимание, что это может привести к некрасивому завершению перехода, когда вам нужно использовать значения, которые намного больше, чем фактическое вычисленное значение. Я заметил это, пытаясь увеличить высоту div от 0 до высоты содержимого, которая сильно различается из-за разных размеров экрана (2 строки на моем мониторе 2560x1440 против> 10 строк на смартфоне). Для этого я остановился на js.
 – 
jpeltoniemi
17 Май 2013 в 14:22
67
Очень уродливое решение, так как оно создает задержку в одном направлении, но не в другом.
 – 
Tim
20 Ноя 2013 в 18:57
108
Это довольно ленивое решение. Я предполагаю, что OP хочет использовать height: auto, потому что увеличенная высота контейнера несколько непредсказуема. Это решение вызовет задержку до того, как анимация станет видимой. Кроме того, видимая продолжительность анимации будет непредсказуемой. Вы получите гораздо более предсказуемые (и, вероятно, более плавные) результаты, если вычислите общую высоту каждого из дочерних узлов контейнера и затем снизите до точного значения высоты.
 – 
Shawn Whinnery
17 Апр 2014 в 02:06

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

242
animuson 25 Фев 2015 в 18:53

Решение, которое я всегда использовал, заключалось в том, чтобы сначала постепенно исчезнуть, а затем сжать значения 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>
159
Samuel Liew 30 Окт 2018 в 01:37
6
Если у вас есть кнопки или любые другие нетекстовые элементы, вы получите нежелательные пробелы, пока не наведете курсор.
 – 
Dennis W
24 Окт 2016 в 01:30
4
Вы можете дополнительно уточнить его, выбрав все дочерние элементы с помощью * и применив другие изменения. Однако на кнопки должен был повлиять мой приведенный выше код, если бы они были правильно стилизованы с помощью em.
 – 
Steven Vachon
25 Окт 2016 в 00:02
Не делай этого. Это не ускорение графического процессора и приведет к очень резкой анимации (как показано во фрагменте этого ответа).
 – 
enyo
1 Ноя 2021 в 12:41

Это решение только для CSS со следующими свойствами:

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

Демо

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

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

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

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


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

  
}

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

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

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

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

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

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

</div>

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

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

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

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

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

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

animation as described above

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

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

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

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

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

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

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

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

126
TylerH 8 Окт 2021 в 17:30
76
Я бы хотел, чтобы вы могли сократить (упростить) свое решение или, по крайней мере, пример кода - похоже, что 90% примера кода не имеют отношения к вашему ответу.
 – 
Gil Epshtain
30 Июл 2018 в 18:16
3
Для кого-то, кто выполняет обучающую миссию, это хороший ответ по нескольким причинам. Во-первых, это полный пример кода «из реальной жизни». Кто-то может взять этот код, поэкспериментировать с ним и узнать больше. И детали в объяснении ... прекрасно детализированы. спасибо, @balpha, что нашли время для этого ответа :)
 – 
James Walker
11 Окт 2021 в 01:16

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

102
Spencer O'Reilly 11 Дек 2017 в 21:38
10
Поскольку это зависит от javascript, вы также можете легко добавить measureWrapper с помощью javascript!
 – 
Quickredfox
30 Апр 2013 в 01:23
23
Вы можете обойтись без обертки. Просто: функция growDiv () {var growDiv = document.getElementById ('grow'); если (growDiv.clientHeight) {growDiv.style.height = 0; } еще {growDiv.style.height = growDiv.scrollHeight + 'px'; }}
 – 
user1742529
17 Июн 2015 в 12:30

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

56
Joran Den Houting 31 Окт 2013 в 14:12
23
За исключением того, что здесь вы вообще не анимируете высоту. Вы анимируете заполнение ... оно может исчезнуть просто так, потому что оно может анимироваться от текущего состояния до 0, но если вы внимательно посмотрите, когда он расширяется, он открывается с текстом, а затем отступы только анимируются .. потому что это не не знаю, как анимировать от 0 до авто .... нужен числовой диапазон ... вот как работает анимация.
 – 
Rob R
15 Дек 2014 в 19:17

Принятый ответ работает в большинстве случаев, но он не работает, когда ваш 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>
54
Oleg Vaskevich 20 Авг 2015 в 01:37
Вы можете использовать clientHeight
 – 
Tom
30 Апр 2020 в 10:06
Это дает очень хороший результат. Но JavaScript по большей части похож на машинный код. Как вы могли переписать код, как будто вы говорите по-английски (читаемый код)?
 – 
klewis
9 Мар 2021 в 16:37

Мое обходное решение - перейти 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>
49
amn 25 Окт 2021 в 11:19

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

43
amn 19 Авг 2021 в 15:17
11
Вы не нашли его в других ответах здесь, потому что для взаимодействия с DOM с использованием свойства Element.scrollHeight требуется JavaScript, и, как ясно сказано в вопросе, они хотят сделать это без JavaScript.
 – 
TylerH
6 Июл 2016 в 00:12

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

Нет 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>
34
Vivek Maharajh 26 Ноя 2017 в 10:02

На момент публикации я уже получил более 30 ответов, но я чувствую, что мой ответ лучше уже принятого ответа Джейка.

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

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

Это означает, что используются как 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>
25
Community 23 Май 2017 в 15:10

Используйте max-height с разной скоростью перехода и задержкой для каждого состояния.

HTML:

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

CSS:

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

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

См. Пример: http://jsfiddle.net/0hnjehjc/1/

39
malihu 17 Дек 2014 в 02:35
17
Проблема здесь в том, что для того, чтобы у вас было достаточно места в динамической среде, вам нужно использовать нелепые максимальные высоты, такие как 999999px. Это, с другой стороны, сместит вашу анимацию, потому что кадры рассчитываются на основе этого значения. Таким образом, вы можете получить "задержку" анимации в одном направлении и очень быстрое завершение в другом направлении (corr: time-functions)
 – 
Julian F. Weinert
24 Июн 2015 в 12:34

Хорошо, думаю, я придумал очень простой ответ ... нет 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>
20
VIDesignz 2 Авг 2015 в 01:35
13
Это будет работать до тех пор, пока высота элемента не превысит его ширину. Это основа того, как поля рассчитываются с использованием процентов: они рассчитываются на основе ширины элемента. Таким образом, если у вас есть элемент шириной 1000 пикселей, то элемент в 1100 пикселей будет слишком большим для этого решения, что означает, что вам придется увеличить это отрицательное верхнее поле. По сути, это та же проблема, что и при использовании высоты или максимальной высоты.
 – 
dudewad
19 Авг 2015 в 23:55

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

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

И наведение:

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

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

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

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

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

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

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

16
Sijav 8 Ноя 2018 в 02:26

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

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}
9
Joran Den Houting 31 Окт 2013 в 14:03
2
Это не будет переходить height, только max-height. height мгновенно перейдет с 0 на auto, а max-height выполнит переход, который кажется, работает , но создает ту же проблему, что и другие ответы. адресовать.
 – 
Michael Johansen
18 Авг 2021 в 15:51

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

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

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

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

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

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

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

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

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

(function(doc){

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

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

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

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

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

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

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

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

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

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

})(document);

/ * Код для ДЕМО * /

    document.addEventListener('click', function(e){
      if (e.target.nodeName == 'BUTTON') {
        var next = e.target.nextElementSibling;
        next.hasAttribute('reveal') ? next.removeAttribute('reveal') : next.setAttribute('reveal', '');
      }
    }, false);
5
csuwldcat 18 Сен 2014 в 22:35
15
Я хочу проголосовать за это, но вместо ответа на вопрос о том, как заставить его работать, вы поделились плагином, который вы написали, чтобы заставить его работать. Нам, любопытным, остаётся перепроектировать ваш плагин, что не очень весело. Я хотел бы, чтобы вы обновили свой ответ, чтобы он содержал больше объяснений того, что делает ваш плагин и почему. Измените код, чтобы он был более понятным. Например, у вас есть целый раздел кода, который просто записывает статический CSS. Я бы предпочел увидеть CSS, чем код, который его генерирует. Вы можете опустить скучные части, такие как повторение для всех префиксов браузера.
 – 
gilly3
9 Янв 2015 в 03:39

Решение Flexbox

Плюсы:

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

Минусы:

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

Это работает так: всегда есть flex-base: 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

11
Lee Comstock 3 Май 2018 в 23:52
Мне нравится это решение. Вместе с абсолютным позиционированием, вложенными списками и событиями-указателями мне удалось получить довольно приятное меню. Я не нашел много минусов. Кто-нибудь?
 – 
Pepe
31 Дек 2021 в 19:12

Вот решение, которое я только что использовал в сочетании с 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 }
4
HandiworkNYC.com 3 Ноя 2011 в 03:58

В этом решении используется несколько приемов:

  • padding-bottom:100% "взломать", где проценты определяются в терминах текущей ширины элемента. Дополнительная информация об этом методе.
  • термоусадочная упаковка с плавающей запятой (требуется дополнительный 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>
6
TylerH 6 Дек 2021 в 17:48
2
Как сказал ваш источник, «отзывчивый квадрат» работает только в том случае, если у вас есть квадратный контент. Так что это даже не близко к принятому ответу ...
 – 
Gaeguri
14 Окт 2021 в 17:16

Решение, состоящее из одного предложения: Использовать переход с отступом . Этого достаточно для большинства случаев, таких как аккордеон, и даже лучше, потому что это быстро из-за того, что значение заполнения часто невелико.

Если вы хотите, чтобы процесс анимации был лучше, просто увеличьте значение отступа.

.parent{ border-top: #999 1px solid;}
h1{ margin: .5rem; font-size: 1.3rem}
.children {
  height: 0;
  overflow: hidden;
  background-color: #dedede;
  transition: padding .2s ease-in-out, opacity .2s ease-in-out;
  padding: 0 .5rem;
  opacity: 0;
}
.children::before, .children::after{ content: "";display: block;}
.children::before{ margin-top: -2rem;}
.children::after{ margin-bottom: -2rem;}
.parent:hover .children {
  height: auto;
  opacity: 1;
  padding: 2.5rem .5rem;/* 0.5 + abs(-2), make sure it's less than expected min-height */
}
<div class="parent">
  <h1>Hover me</h1>
  <div class="children">Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>
<div class="parent">
  <h1>Hover me(long content)</h1>
  <div class="children">Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>
  </div>
</div>
<div class="parent">
  <h1>Hover me(short content)</h1>
  <div class="children">Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>
9
dallaslu 15 Апр 2020 в 08:44

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

ОК! Я знаю, что эта проблема стара как Интернет, но я думаю, что у меня есть решение, которое я превратил в плагин под названием mutant -переход. Мое решение устанавливает атрибуты 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 +.

Скрипки!

5
JonTroncoso 19 Май 2015 в 10:47
16
Обычно, когда кто-то спрашивает, как сделать что-то «без JavaScript», это означает, что решение должно работать в браузерах, в которых отключен JavaScript. Это не значит «без написания собственных сценариев». Таким образом, утверждение, что ваш плагин можно использовать без использования JavaScript, в лучшем случае вводит в заблуждение - учитывая, что это плагин JavaScript.
 – 
BoltClock
1 Апр 2017 в 09:19
Я должен уточнить: когда я говорю, что вам не нужно использовать какой-либо специальный javascript, я имею в виду, что вам не нужно писать какой-либо javascript. просто включите библиотеку JS и укажите, какие атрибуты вы хотите просмотреть в HTML. Вам не нужно использовать CSS с фиксированной высотой или что-то придумывать. просто стиль и вперед.
 – 
JonTroncoso
4 Апр 2017 в 00:05

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

Можно переместить сворачиваемое содержимое во внутренний 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/

5
user3336882 5 Авг 2015 в 15:13

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

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

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

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

4
Charley 27 Май 2011 в 05:13

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

6
Jonatas Walker 23 Ноя 2015 в 11:33

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

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

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

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

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

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

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

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

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

#menu > ul.open {
  height: auto;
}
<div id="menu">
  <a>hover me</a>
  <ul>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
  </ul>
</div>
5
shunryu111 6 Апр 2021 в 13:41

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

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

Не работает переход с пикселей на% или на авто. Вам нужно использовать ту же единицу измерения.

4
TylerH 28 Апр 2021 в 20:52

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

Примерно так, псевдокод

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

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

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

5
Jonatas Walker 23 Ноя 2015 в 11:31
2
Мы будем очень благодарны за рабочий пример этого.
 – 
Neurotransmitter
26 Июн 2018 в 17:01

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

Изменить Некоторым людям не нравится, как scaleY преобразует контент. Если это проблема, я предлагаю вместо этого использовать clip.

ul {
  clip: rect(auto, auto, 0, auto);
  position: absolute;
  margin: -1rem 0;
  padding: .5rem;

  color: white;

  background-color: rgba(0, 0, 0, 0.8);

  transition-property: clip;
  transition-duration: 0.5s;
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
h3:hover ~ ul,
h3:active ~ ul,
ul:hover {
  clip: rect(auto, auto, 10rem, auto);
}
<h3>Hover here</h3>
<ul>
  <li>This list</li>
  <li>is clipped.</li>
  <li>A clip transition</li>
  <li>will show it</li>
</ul>
<p>
  Some text...
</p>
397
dotnetCarpenter 27 Июл 2021 в 22:38
267
Этот метод лишь частично обеспечивает желаемый эффект, но на самом деле не удаляет пространство. Преобразованный блок действует как относительно позиционированный элемент - пространство занимает независимо от того, как оно масштабируется. Взгляните на этот jsFiddle, который берет ваш первый и просто добавляет внизу фальшивый текст. Обратите внимание на то, что текст под ним не перемещается вверх, когда высота поля масштабируется до нуля.
 – 
animuson
30 Июл 2013 в 00:37
9
Теперь это возможно: jsfiddle.net/gNDX3/1 В основном вам нужно стилизовать элементы в соответствии с тем, что тебе нужно. В CSS / HTML нет серебряной пули или поведения, подобного виджетам.
 – 
dotnetCarpenter
30 Авг 2013 в 20:07
97
Хотя я аплодирую тому, кто пробует разные подходы, реальный эффект и сложности, которые приносит это решение, намного хуже, чем и без того ужасный взлом максимальной высоты. Пожалуйста, не используйте.
 – 
mystrdat
18 Ноя 2013 в 23:53
3
«Теперь это происходит», за исключением того, что содержимое под исчезающим элементом подпрыгивает, прежде чем элемент ускользнет. Иногда это может быть полезно, однако цель переходов состоит в том, чтобы плавно менять визуальные эффекты, а не обменивать один резкий прыжок на другой.
 – 
Patrick Szalapski
2 Май 2021 в 04:51
2
По сути, использование преобразования clip ничем не отличается от простой установки значения max-height. Он по-прежнему страдает от нефиксированной задержки видимой анимации с очень динамичным размером содержимого.
 – 
Monday Fatigue
6 Сен 2021 в 02:52

Вы можете сделать это, создав обратную (свернутую) анимацию с помощью 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>
5
TylerH 24 Фев 2020 в 17:22
1
Отлично, но как отменить раскрытие с помощью анимации?
 – 
ViRuSTriNiTy
15 Июл 2021 в 18:48

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

Таким образом, 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/

8
Joran Den Houting 31 Окт 2013 в 14:36

Согласно MDN Web Docs, auto значения были намеренно исключены из спецификации переходов CSS, поэтому вместо height: auto используйте height: 100% , top или свойство flex в макетах сетки и гибкости.

Развертывание / сворачивание наложения

.grid-container {
  display: grid;
  position: absolute;
}

.content {
  background: aqua;
  height: 0;
  overflow: hidden;
  transition: all 1s ease;
}

span:hover + .grid-container .content {
  height: 100%;
}
<span>Hover over me!</span>

<div class="grid-container">

  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

</div>

<p>Rest of the page content...</p>

Развертывание / сворачивание скользящего наложения

.grid-container {
  display: grid;
  position: absolute;
  overflow: hidden;
  pointer-events: none; /* to enable interaction with elements below the container */
}

.content {
  background: aqua;
  pointer-events: auto;
  position: relative;
  top: -100%;
  transition: all 1s ease;
}

span:hover + .grid-container .content {
  top: 0;
}
<span>Hover over me!</span>

<div class="grid-container">

  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

</div>

<p>Rest of the page content...</p>

Разворачивание / сворачивание в документообороте

html {
  display: grid;
}

body {
  display: flex;
  flex-direction: column;
}

.content {
  background: aqua;
  flex-basis: 0;
  overflow: hidden;
  transition: all 1s ease;
}

span:hover + .content {
  flex: 1;
}
<span>Hover over me!</span>

<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

<p>Rest of the page content...</p>
8
Mori 29 Ноя 2021 в 08:53
Я был в восторге от этого примера: Expanding/collapsing in the document flow, но он не работает, поскольку контейнер имеет определенную высоту, поэтому будет затронут остальной контент, контент вне контейнера,
 – 
Marco Mesen
23 Ноя 2021 в 01:44
Да! Спасибо, что поделились, если я так думаю, в некоторых ситуациях, когда не имеет значения, если вы выходите за пределы в конце контента, в случае, если контент является полной страницей, у вас всегда будет несказанный интервал в конце
 – 
Marco Mesen
23 Ноя 2021 в 20:52
@MarcoMesen: Только что отредактировал мой пример.
 – 
Mori
30 Ноя 2021 в 16:44

Альтернативное решение только для CSS с line-height, padding, opacity и margin:

body {
  background-color: linen;
}

main {
  background-color: white;
}

[id^="toggle_"] ~ .content {
  line-height: 0;
  opacity: 0;
  padding: 0 .5rem;
  transition: .2s ease-out;
}

[id^="toggle_"] ~ .content > p {
  margin: 0;
    transition: .2s ease-out;
}

[id^="toggle_"]:checked ~ .content   {
  opacity: 1;
  padding: .5rem;
  line-height: 1.5;
}

[id^="toggle_"]:checked ~ .content p  {
    margin-bottom: .75rem;
}

[id^="toggle_"] + label {
  display: flex;
  justify-content: space-between;
  padding: 0.5em 1em;
  background: lightsteelblue;
  border-bottom: 1px solid gray;
  cursor: pointer;
}

[id^="toggle_"] + label:before {
  content: "Show";
}

[id^="toggle_"]:checked + label:before {
  content: "Hide";
}

[id^="toggle_"] + label:after {
  content: "\25BC";
}

[id^="toggle_"]:checked + label:after {
  content: "\25B2";
}
<main>
    <div>
        <input type="checkbox" id="toggle_1" hidden>
        <label for="toggle_1" hidden></label>
        <div class="content">
            <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dolor neque, commodo quis leo ut, auctor tincidunt mauris. Nunc fringilla tincidunt metus, non gravida lorem condimentum non. Duis ornare purus nisl, at porta arcu eleifend eget. Integer lorem ante, porta vulputate dui ut, blandit tempor tellus. Proin facilisis bibendum diam, sit amet rutrum est feugiat ut. Mauris rhoncus convallis arcu in condimentum. Donec volutpat dui eu mollis vulputate. Nunc commodo lobortis nunc at ultrices. Suspendisse in lobortis diam. Suspendisse eget vestibulum ex.
            </p>
        </div>
    </div>
    <div>
        <input type="checkbox" id="toggle_2" hidden>
        <label for="toggle_2" hidden></label>
        <div class="content">
            <p>
                Maecenas laoreet nunc sit amet nulla ultrices auctor. Vivamus sed nisi vitae nibh condimentum pulvinar eu vel lorem. Sed pretium viverra eros ut facilisis. In ut fringilla magna. Sed a tempor libero. Donec sapien libero, lacinia sed aliquet ut, imperdiet finibus tellus. Nunc tellus lectus, rhoncus in posuere quis, tempus sit amet enim. Morbi et erat ac velit fringilla dignissim. Donec commodo, est id accumsan cursus, diam dui hendrerit nisi, vel hendrerit purus dolor ut risus. Phasellus mattis egestas ipsum sed ullamcorper. In diam ligula, rhoncus vel enim et, imperdiet porta justo. Curabitur vulputate hendrerit nisl, et ultricies diam. Maecenas ac leo a diam cursus ornare nec eu quam.
            </p>
            <p>Sed non vulputate purus, sed consectetur odio. Sed non nibh fringilla, imperdiet odio nec, efficitur ex. Suspendisse ut dignissim enim. Maecenas felis augue, tempor sit amet sem fringilla, accumsan fringilla nibh. Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus in ante molestie tincidunt. Morbi luctus orci eu egestas dignissim. Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit.
            </p>
            <p>Aenean aliquam risus id consectetur sagittis. Aliquam aliquam nisl eu augue accumsan, vel maximus lorem viverra. Aliquam ipsum dolor, tempor et justo ac, fermentum mattis dui. Etiam at posuere ligula. Vestibulum tortor metus, viverra vitae mi non, laoreet iaculis purus. Praesent vel semper nibh. Curabitur a congue lacus. In et pellentesque lorem. Morbi posuere felis non diam vulputate, non vulputate ex vehicula. Vivamus ultricies, massa id sagittis consequat, sem mauris tincidunt nunc, eu vehicula augue quam ut mauris.
            </p>
        </div>
    </div>
        <div>
        <input type="checkbox" id="toggle_3" hidden>
        <label for="toggle_3" hidden></label>
        <div class="content">
            <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dolor neque, commodo quis leo ut, auctor tincidunt mauris. Nunc fringilla tincidunt metus, non gravida lorem condimentum non. Duis ornare purus nisl, at porta arcu eleifend eget. Integer lorem ante, porta vulputate dui ut, blandit tempor tellus. Proin facilisis bibendum diam, sit amet rutrum est feugiat ut. Mauris rhoncus convallis arcu in condimentum. Donec volutpat dui eu mollis vulputate. Nunc commodo lobortis nunc at ultrices. Suspendisse in lobortis diam. Suspendisse eget vestibulum ex.
            </p>
            <p>Sed non vulputate purus, sed consectetur odio. Sed non nibh fringilla, imperdiet odio nec, efficitur ex. Suspendisse ut dignissim enim. Maecenas felis augue, tempor sit amet sem fringilla, accumsan fringilla nibh. Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus in ante molestie tincidunt. Morbi luctus orci eu egestas dignissim. Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit.
            </p>
        </div>
    </div>
</main>
5
Ali Klein 28 Апр 2021 в 21:36