Я пытаюсь сделать слайд <ul>
с помощью переходов CSS.
<ul>
начинается с height: 0;
, При зависании высота устанавливается на height:auto;
, Однако это заставляет его просто появляться, а не переход,
Если я делаю это с height: 40px;
height: auto;
, то он будет скользить до height: 0;
, а затем внезапно перепрыгните на правильную высоту.
Как еще я могу это сделать без использования JavaScript?
#child0 {
height: 0;
overflow: hidden;
background-color: #dedede;
-moz-transition: height 1s ease;
-webkit-transition: height 1s ease;
-o-transition: height 1s ease;
transition: height 1s ease;
}
#parent0:hover #child0 {
height: auto;
}
#child40 {
height: 40px;
overflow: hidden;
background-color: #dedede;
-moz-transition: height 1s ease;
-webkit-transition: height 1s ease;
-o-transition: height 1s ease;
transition: height 1s ease;
}
#parent40:hover #child40 {
height: auto;
}
h1 {
font-weight: bold;
}
The only difference between the two snippets of CSS is one has height: 0, the other height: 40.
<hr>
<div id="parent0">
<h1>Hover me (height: 0)</h1>
<div id="child0">Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>
</div>
</div>
<hr>
<div id="parent40">
<h1>Hover me (height: 40)</h1>
<div id="child40">Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>
</div>
</div>
Используйте max-height
в преобразовании, а не в height
. И установите значение на max-height
на нечто большее, чем ваша коробка когда-либо появится.
См. Демонстрацию JSFiddle, предоставленную Крисом Джорданом в другом ответе здесь.
#menu #list {
max-height: 0;
transition: max-height 0.15s ease-out;
overflow: hidden;
background: #d5d5d5;
}
#menu:hover #list {
max-height: 500px;
transition: max-height 0.25s ease-in;
}
<div id="menu">
<a>hover me</a>
<ul id="list">
<!-- Create a bunch, or not a bunch, of li to see the timing. -->
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
</div>
Вместо этого вы должны использовать scaleY.
HTML:
<p>Here (scaleY(1))</p>
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
CSS
ul {
background-color: #eee;
transform: scaleY(0);
transform-origin: top;
transition: transform 0.26s ease;
}
p:hover ~ ul {
transform: scaleY(1);
}
Я сделал версию префикса вышеприведенного кода на jsfiddle, http://jsfiddle.net/dotnetCarpenter/PhyQc/9/ и изменил ваш jsfiddle, чтобы использовать scaleY вместо высоты, http://jsfiddle.net/dotnetCarpenter/7cnfc/206/.
В настоящее время вы не можете анимации по высоте, когда одна из задействованных высот auto
, вы должны установить две явные высоты.
Решение, которое я всегда использовал, состояло в том, чтобы сначала постепенно затухать, а затем уменьшать font-size
, padding
и значения margin
. Это не выглядит так же, как стирание, но работает без статической height
или max-height
.
Рабочий пример:
/* final display */
#menu #list {
margin: .5em 1em;
padding: 1em;
}
/* hide */
#menu:not(:hover) #list {
font-size: 0;
margin: 0;
opacity: 0;
padding: 0;
/* fade out, then shrink */
transition: opacity .25s,
font-size .5s .25s,
margin .5s .25s,
padding .5s .25s;
}
/* reveal */
#menu:hover #list {
/* unshrink, then fade in */
transition: font-size .25s,
margin .25s,
padding .25s,
opacity .5s .25s;
}
<div id="menu">
<b>hover me</b>
<ul id="list">
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
</div>
<p>Another paragraph...</p>
Вы можете, с небольшим количеством не-семантического 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
.
replaceChild
и следующей техникой, чтобы добавить div-оболочку без нарушения каких-либо существующих ссылок на элементы DOM: stackoverflow.com/questions/6938248/… . Кроме того, мне не понравилось, как я не мог открыть закрывающий div в среднем потоке, поэтому я добавил логическое свойство isOpening к объекту DOM, а затем использовал его, чтобы узнать, открывался ли div или закрывался. Это дало мне намного больше контроля над модулем аккордеона, который я построил. Во всяком случае, еще раз спасибо. Отличный ответ!
Я знаю, что это тридцать-точный ответ на этот вопрос, но я думаю, что это того стоит, так что и здесь. Это CSS-only решение со следующими свойствами:
transform: scaleY(0)
), поэтому он делает правильную вещь, если есть содержимое после сбрасываемого элемента.height: auto
) состоянии весь контент всегда имеет правильную высоту (в отличие от, например, если вы выберите a max-height
, который оказывается слишком низким). И в сжатом состоянии высота равна нулю, как и должно быть.Вот демо с тремя разборными элементами, все разные высоты, которые используют один и тот же CSS. Вы можете нажать "полная страница" после нажатия "выполнить сниппет". Обратите внимание, что JavaScript только переключает класс collapsed
CSS, там нет измерений. (Вы можете сделать эту точную демонстрацию без какого-либо JavaScript вообще, используя флажок или :target
). Также обратите внимание, что часть CSS, ответственная за переход, довольно короткая, и для HTML требуется только один дополнительный элемент оболочки.
$(function () {
$(".toggler").click(function () {
$(this).next().toggleClass("collapsed");
$(this).toggleClass("toggled"); // this just rotates the expander arrow
});
});
.collapsible-wrapper {
display: flex;
overflow: hidden;
}
.collapsible-wrapper:after {
content: '';
height: 50px;
transition: height 0.3s linear, max-height 0s 0.3s linear;
max-height: 0px;
}
.collapsible {
transition: margin-bottom 0.3s cubic-bezier(0, 0, 0, 1);
margin-bottom: 0;
max-height: 1000000px;
}
.collapsible-wrapper.collapsed > .collapsible {
margin-bottom: -2000px;
transition: margin-bottom 0.3s cubic-bezier(1, 0, 1, 1),
visibility 0s 0.3s, max-height 0s 0.3s;
visibility: hidden;
max-height: 0;
}
.collapsible-wrapper.collapsed:after
{
height: 0;
transition: height 0.3s linear;
max-height: 50px;
}
/* END of the collapsible implementation; the stuff below
is just styling for this demo */
#container {
display: flex;
align-items: flex-start;
max-width: 1000px;
margin: 0 auto;
}
.menu {
border: 1px solid #ccc;
box-shadow: 0 1px 3px rgba(0,0,0,0.5);
margin: 20px;
}
.menu-item {
display: block;
background: linear-gradient(to bottom, #fff 0%,#eee 100%);
margin: 0;
padding: 1em;
line-height: 1.3;
}
.collapsible .menu-item {
border-left: 2px solid #888;
border-right: 2px solid #888;
background: linear-gradient(to bottom, #eee 0%,#ddd 100%);
}
.menu-item.toggler {
background: linear-gradient(to bottom, #aaa 0%,#888 100%);
color: white;
cursor: pointer;
}
.menu-item.toggler:before {
content: '';
display: block;
border-left: 8px solid white;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
width: 0;
height: 0;
float: right;
transition: transform 0.3s ease-out;
}
.menu-item.toggler.toggled:before {
transform: rotate(90deg);
}
body { font-family: sans-serif; font-size: 14px; }
*, *:after {
box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="menu">
<div class="menu-item">Something involving a holodeck</div>
<div class="menu-item">Send an away team</div>
<div class="menu-item toggler">Advanced solutions</div>
<div class="collapsible-wrapper collapsed">
<div class="collapsible">
<div class="menu-item">Separate saucer</div>
<div class="menu-item">Send an away team that includes the captain (despite Riker 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
само по себе имеет две проблемы:
margin-bottom: -2000px
не скроет все - там будут видимые вещи даже в свернутом случае. Это небольшое исправление, которое мы сделаем позже.Фиксирование этой второй проблемы - это то, где происходит второй переход, и этот переход концептуально нацелен на минимальную высоту обертки ( "концептуально", потому что мы на самом деле не используем свойство min-height
для этого, подробнее об этом позже).
Здесь анимация, показывающая, как объединение перехода нижнего края с минимальным переходом высоты, равное продолжительности, дает нам комбинированный переход от полной высоты к нулевой высоте, которая имеет одинаковую продолжительность.
Левая панель показывает, как отрицательное нижнее поле подталкивает снизу вверх, уменьшая видимую высоту. Средняя полоса показывает, как минимальная высота гарантирует, что в свертывающемся случае переход не заканчивается на ранней стадии, а в расширяющемся случае переход не задерживается. На правой панели показано, как комбинация этих двух параметров приводит к переходу окна с полной высоты на нулевую высоту за правильное время.
Для моей демонстрации я установил 50px как верхнее минимальное значение высоты. Это второе магическое число, и оно должно быть ниже, чем высота окна. 50px также кажется разумным; кажется маловероятным, что вы очень часто захотите сделать элемент разборчивым, который не имеет даже 50 пикселей в первую очередь.
Как вы можете видеть в анимации, результирующий переход является непрерывным, но он не является дифференцируемым - в тот момент, когда минимальная высота равна полной высоте, скорректированной по нижнему краю, происходит внезапное изменение скорости, Это очень заметно в анимации, потому что он использует функцию линейного синхронизма для обоих переходов и потому, что весь переход происходит очень медленно. В фактическом случае (моя демонстрация сверху) переход занимает всего 300 мс, а переход нижнего края не является линейным. Я играл с множеством различных функций синхронизации для обоих переходов, и те, в которых я оказался, чувствовали, что они лучше всего подходят для самых разных случаев.
Остается решить две проблемы:
Мы решаем первую задачу, предоставляя контейнерный элемент 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, что делает его довольно бессмысленным упражнением.
Мое обходное решение - переход 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>
max-height
only! Контент, который я оживляю, не так уж и гибок :)
.slideUp
, .slideDown
и .slideToggle
, которые не делают высоту статичной. Попробуй это. По сути, это всего лишь одна строка, которая делает то же самое и расширяет ее до точки, где она анимируется, даже когда вы расширяете контент, не должно быть слишком сложной задачей. Так как вы уже используете jQuery ...
Визуальное обходное решение для анимации высоты с использованием переходов 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)
Принятый ответ работает в большинстве случаев, но он не очень хорошо работает, когда ваш 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>
document.getElementById('mydiv')
или $('#mydiv').get()
), и функция переключается между его скрытием / показом. Если вы установили CSS-переходы, элемент будет анимирован автоматически.
Используйте 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/
999999px
. Это, с другой стороны, сместит вашу анимацию, потому что кадры рассчитываются по этому значению. Таким образом, у вас может получиться анимация «задержки» в одном направлении и действительно быстрый конец в другом направлении (corr: timer-functions)
Было мало упоминания о свойстве 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
(которые в настоящее время получают некоторую особую обработку).
Element.scrollHeight
требует JavaScript, и, как ясно указывает вопрос, они хотят сделать это без JavaScript.
scrollHeight
, выполнив более тщательный поиск в этот раз, хотя код, использующий его, кажется довольно запутанным и определенно содержит больше JavaScript, чем необходимо сегодня. В любом случае, я полагаю, что вы правы с no-JavaScript, но без Javascript вы ограничены :active
и :focus
и, возможно, парой других псевдоклассов, поэтому мне интересно, что именно означает «No JavaScript». Как в "чистой CSS-анимации"? Потому что установка стиля в JavaScript все еще является чистой и разлагаемой CSS-анимацией.
Нет жестко закодированных значений.
Нет 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>
Поскольку я публикую это, есть уже более 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>
translateY
за scale
потому что мне не нравилось, как scale
дает такой эффект сжатия.
Хорошо, поэтому я думаю, что придумал супер простой ответ...
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>
РЕДАКТИРОВАТЬ: прокрутите вниз, чтобы получить обновленный ответ
Я делал выпадающий список и видел этот пост... много разных ответов, но я решил поделиться своим выпадающим списком тоже... Он не идеален, но по крайней мере он будет использовать только 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
надеюсь, кто-то найдет это полезным в будущем.
Вы можете перейти с высоты: от 0 до высоты: автоматически, при условии, что вы также обеспечиваете минимальную высоту и максимальную высоту.
div.stretchy{
transition: 1s linear;
}
div.stretchy.hidden{
height: 0;
}
div.stretchy.visible{
height: auto;
min-height:40px;
max-height:400px;
}
Я думаю, что придумал действительно прочное решение
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 +.
скрипки!
Решение Flexbox
Плюсы:
Минусы:
Способ, которым он работает, - это всегда иметь гибкую основу: 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>
Здесь вы можете перейти от любой начальной высоты, включая 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);
Вы должны использовать 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/
Ответ Джейка для анимации 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/
Я понимаю, что эта ветка стареет, но она высоко ценится в некоторых поисковых процессах Google, поэтому я считаю, что это стоит обновить.
Вы также просто получаете/устанавливаете собственную высоту элемента:
var load_height = document.getElementById('target_box').clientHeight;
document.getElementById('target_box').style.height = load_height + 'px';
Вы должны сбросить этот Javascript сразу после тега закрытия target_box в встроенном теге script.
Недавно я перешел на max-height
на элементы li
, а не на обертку ul
.
Причиной является то, что задержка для малого max-heights
гораздо менее заметна (если вообще) по сравнению с большим max-heights
, и я также могу установить значение max-height
относительно font-size
для li
вместо некоторого произвольного огромного числа с помощью ems
или rems
.
Если размер моего шрифта 1rem
, я установлю max-height
на что-то вроде 3rem
(для размещения завернутого текста). Здесь вы можете увидеть пример:
Я смог это сделать. У меня есть 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
, когда он скользит вниз.
Развернувшись на ответ @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/
Здесь решение, которое я использовал только в сочетании с 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 }
Я не читал все подробно, но у меня была эта проблема в последнее время, и я сделал следующее:
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 делает его идеальным....
Помните, что всегда есть работа вокруг...; )
Надеюсь, что кто-то найдет это полезным
Это не совсем "решение" проблемы, но более обходное решение. Он работает только как написанный с текстом, но может быть изменен для работы с другими элементами по мере необходимости. Я уверен.
.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, в настоящее время невозможно, но преобразование содержимого внутри - это, следовательно, переход размера шрифта.
Решение максимальной высоты от Джейка хорошо работает, если жестко закодированное Значение максимальной высоты не намного больше реальной высоты (поскольку в противном случае возникают нежелательные задержки и проблемы времени). С другой стороны, если жестко закодированное значение случайно не больше реальной высоты, элемент не будет полностью раскрываться.
Следующее решение для 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
Я считаю, что решение height:auto/max-height
будет работать только в том случае, если вы расширяете область больше, чем height
, которую вы хотите ограничить.
Если у вас есть max-height
из 300px
, но выпадающее окно со списком, которое может возвращать 50px
, то max-height
вам не поможет, 50px
является переменной в зависимости от количества элементов, вы можете прийти в невозможную ситуацию, когда я не могу ее исправить, потому что height
не фиксирован, height:auto
было решением, но я не могу использовать переходы с этим.
Установите высоту в 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%; /**/
}
Кажется, что нет правильного решения. Подход 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>
Это регулярная проблема, которую я решил как это
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;
}
Как насчет высоты, вы используете что-то вроде ниже
#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
. Одновременно вы можете добавить переход для высоты отдельно или только вы все.
Отметьте мой пост по поводу некоторого смежного вопроса.
В принципе, начинайте с 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;
}
}
Стиль может не поддерживаться кросс-браузер. Вот живой пример для этого кода:
МАЛЕНЬКИЕ РЕШЕНИЯ 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; }
}
}
В большинстве случаев это будет выполнять эту работу. Надеюсь, это поможет!
Я встретил эту проблему и нашел способ обхода.
Сначала я попытался использовать 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);
}
Я рассматривал эту проблему некоторое время сегодня и наткнулся на это решение:
Используйте максимальную высоту и динамически устанавливайте максимальную высоту на основе расчетной высоты содержимого контейнера
$(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;
Таким образом, вы избегаете глянцевой анимации от дороги до большой высоты. И вы не рискуете обрезать свой контент.
Я получил эту работу, установив 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;
}
}
Я понимаю, что вопрос требует решения без 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
Вот мое решение. Предыдущий с 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>
Это то, что работает для меня:
.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
В этих решениях используется 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).
Пример короткого кода:
.slider ul {
overflow: hidden;
-webkit-transition: max-height 3.3s ease;
}
.slider.hide ul {
max-height: 0px;
}
.slider.show ul {
max-height: 1000px;
}
Если количество "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>
Я также сделал это с 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});
});
Надеюсь, это поможет кому-то:)
это то, что я использовал.
В принципе, я получаю все высоты элементов элементов, суммирую их, а затем устанавливаю максимальную высоту для элемента, переопределяя класс (вы можете создать собственный класс, чтобы иметь разные экземпляры).
Проверьте это.
<!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>
height:auto/max-height
будет работать только в том случае, если вы расширяете область больше, чемheight
вы хотите ограничить. Если у васmax-height
300px
, но выпадающий список со списком, который может вернуть50px
, тогдаmax-height
не поможет,50px
является переменной величиной в зависимости от количества элементов, вы можете оказаться в невозможной ситуации, когда я не могу исправить это, потому чтоheight
не фиксирована,height:auto
было решением, но я не могу использовать переходы с этим.