Как вы хотите исключить оба слова, вам понадобится объединение:
^/(?!ignoreme$)(?!ignoreme2$)[a-z0-9]+$
Теперь оба условия должны быть истинными (ни ignoreme , ни ignoreme2 разрешено), чтобы иметь соответствие.
Это не совсем «решение» проблемы, а скорее обходной путь. Я уверен, что он работает только так, как написано с текстом, но его можно изменить для работы с другими элементами.
.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 и переходите на него вместо высоты, или максимальной высоты, или масштаба Y () и т. д. в достаточно быстром темпе, чтобы высота трансформировалась в то, что вы хотите. Преобразовать фактическую высоту с помощью CSS в auto в настоящее время невозможно, но преобразование содержимого внутри, следовательно, переход размера шрифта.
Я получил эту работу, установив max-height на none, получив высоту, заново установив max-height на рассчитанную высоту. Префектно работает для меня. Я получил эту работу для меню Accordeon, с <h5>
в качестве переключателя, расширяющего <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);
});
МЕНЬШЕ:
div {
> div {
max-height: 0px;
overflow: hidden;
.transition(all 0.3s ease-in-out);
}
&.temp_expanded {
> div {
max-height: none;
}
}
Как насчет вместо высоты, вы используете что-то вроде ниже одного
#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
. Одновременно вы можете добавить переход по высоте индивидуально или только вам всем.
Принятый ответ работает в большинстве случаев, но он не работает, когда ваш 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>
.child
& amp; .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
, когда он скользит вниз.
Расширяя ответ @ 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/
Решение по максимальной высоте от Джейка хорошо работает, если жестко заданное значение максимальной высоты не намного превышает реальную высоту (поскольку в противном случае возникают нежелательные задержки и проблемы с синхронизацией). С другой стороны, если жестко запрограммированное значение случайно не превышает реальную высоту, элемент не откроется полностью.
Следующее решение только для CSS также требует жестко заданного размера, который должен быть больше, чем большинство существующих реальных размеров. Однако это решение также работает, если реальный размер в некоторых ситуациях превышает жестко заданный размер. В этом случае переход может немного подскочить, но он никогда не оставит частично видимый элемент. Таким образом, это решение также может быть использовано для неизвестного контента, например, из базы данных, где вы просто знаете, что контент обычно не больше, чем х пикселей, но есть исключения.
Идея состоит в том, чтобы использовать отрицательное значение для margin-bottom (или margin-top для слегка отличающейся анимации) и поместить элемент содержимого в средний элемент с переполнением: hidden. Отрицательное поле элемента содержимого уменьшает высоту среднего элемента.
В следующем коде используется переход на полях с -150px на 0px. Это само по себе работает нормально, если элемент содержимого не превышает 150 пикселей. Кроме того, он использует переход на max-height для среднего элемента от 0px до 100%. Это, наконец, скрывает средний элемент, если элемент содержимого превышает 150px. Для максимальной высоты переход используется только для задержки его применения на секунду при закрытии, а не для получения плавного визуального эффекта (и, следовательно, он может работать от 0px до 100%).
CSS:
.content {
transition: margin-bottom 1s ease-in;
margin-bottom: -150px;
}
.outer:hover .middle .content {
transition: margin-bottom 1s ease-out;
margin-bottom: 0px
}
.middle {
overflow: hidden;
transition: max-height .1s ease 1s;
max-height: 0px
}
.outer:hover .middle {
transition: max-height .1s ease 0s;
max-height: 100%
}
HTML:
<div class="outer">
<div class="middle">
<div class="content">
Sample Text
<br> Sample Text
<br> Sample Text
<div style="height:150px">Sample Test of height 150px</div>
Sample Text
</div>
</div>
Hover Here
</div>
Значение для поля должно быть отрицательным и максимально приближенным к реальной высоте элемента содержимого. Если оно (абсолютное значение) больше, то возникают такие же проблемы с задержкой и синхронизацией, как и в решениях с максимальной высотой, которые, однако, могут быть ограничены, если размер в жестком коде не намного больше, чем реальный. Если абсолютное значение для margin-bottom меньше, чем реальная высота, переход немного увеличивается. В любом случае после перехода элемент содержимого либо полностью отображается, либо полностью удаляется.
Подробнее см. В моем блоге http://www.taccgl.org/blog/css_transition_display.html#combined_height
.Установите высоту на авто и измените максимальную высоту.
Проверено на 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
, так как я расширяю текстовый блок неизвестной длины. 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);
}
Если количество «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>
Визуальное обходное решение для анимации высоты с использованием CSS3-переходов состоит в том, чтобы вместо этого анимировать отступы.
Вы не совсем получаете эффект полного стирания, но игра с значениями длительности перехода и заполнения должна приблизить вас достаточно близко. Если вы не хотите явно устанавливать высоту / максимальную высоту, это должно быть то, что вы ищете.
div {
height: 0;
overflow: hidden;
padding: 0 18px;
-webkit-transition: all .5s ease;
-moz-transition: all .5s ease;
transition: all .5s ease;
}
div.animated {
height: auto;
padding: 24px 18px;
}
http://jsfiddle.net/catharsis/n5XfG/17/ (сброшен со Stephband выше jsFiddle)
Для чисто CSS-решения, которое анимирует max-height
, у которого нет большой задержки, я бы посоветовал установить разумное значение max-height
при наведении, где-то около 500 пикселей или примерно или чуть больше, чем высота большинства элементы, которые вы хотите анимировать, имеют большую прокрутку содержимого путем установки overflow-y
в auto
после завершения анимации с задержкой 0,5 с.
Затем установите время перехода около 0,3 с (или немного медленнее, если расширение приведет к перемещению другого контента на вашей странице) с экспоненциальной кривой кубического безье при открытии и упрощением - в кривой кубического Безье и несколько быстрее при закрытии, например, 0,15 с, например, когда люди отбрасывают что-то со страницы, они, как правило, не хотят ждать, пока они не исчезнут.
Эти быстрые анимации будут по-прежнему видны пользователю и сводят к минимуму эффект любой задержки максимальной высоты, вызывающей замедление работы вашей страницы.
Код будет выглядеть примерно так:
#child0 {
max-height: 0;
overflow-y: hidden;
background-color: #dedede;
-webkit-transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
-moz-transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
-o-transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
}
#parent0:hover #child0 {
max-height: 500px;
overflow-y: auto;
-webkit-transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
-moz-transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
-o-transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
}
Нет жестко закодированных значений.
Нет JavaScript.
Нет приближений.
Хитрость заключается в том, чтобы использовать скрытый & amp; дублируется 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>
Flexbox Solution
Плюсы:
Минусы:
То, как он работает, всегда имеет flex-based: auto на элемент с содержанием, и вместо этого переходы flex-grow и flex-shrink.
Редактировать: улучшена JS Fiddle, вдохновленная интерфейсом Xbox One.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
transition: 0.25s;
font-family: monospace;
}
body {
margin: 10px 0 0 10px;
}
.box {
width: 150px;
height: 150px;
margin: 0 2px 10px 0;
background: #2d333b;
border: solid 10px #20262e;
overflow: hidden;
display: inline-flex;
flex-direction: column;
}
.space {
flex-basis: 100%;
flex-grow: 1;
flex-shrink: 0;
}
p {
flex-basis: auto;
flex-grow: 0;
flex-shrink: 1;
background: #20262e;
padding: 10px;
width: 100%;
text-align: left;
color: white;
}
.box:hover .space {
flex-grow: 0;
flex-shrink: 1;
}
.box:hover p {
flex-grow: 1;
flex-shrink: 0;
}
<div class="box">
<div class="space"></div>
<p>
Super Metroid Prime Fusion
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
Resident Evil 2 Remake
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
Yolo The Game
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
Final Fantasy 7 Remake + All Additional DLC + Golden Tophat
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
DerpVille
</p>
</div>
В настоящее время вы не можете анимировать по высоте, если одна из задействованных высот равна auto
, вам нужно установить две явные высоты.
Вот способ перехода с любой начальной высоты, включая 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-файл на свою страницу - все это просто Works ™
/ * Код для высоты: авто; Переход * /
(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);
/ * Код для 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);
РЕДАКТИРОВАТЬ: прокрутите вниз, чтобы получить обновленный ответ
Я делал выпадающий список и видел это сообщение ... много разных ответов, но я решил поделиться своим выпадающим списком тоже ... Это не идеально но по крайней мере он будет использовать только 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;
}
и hover:
#menu > li:hover div {
transition: 0.5s;
-webkit-transform:translateY(0);
}
, и так как ul height установлен на его содержание может перебрать содержимое вашего тела, поэтому я сделал это для ul:
#menu ul {
transition: 0s 1.5s;
visibility:hidden;
overflow:hidden;
}
и hover:
#menu > li:hover ul {
transition:none;
visibility:visible;
}
во второй раз после перехода с задержкой, и он будет скрыт после моего удаления нижний список был закрыт ...
Надеюсь, позже кто-нибудь получит пользу от этого.
РЕДАКТИРОВАТЬ: Я просто не могу поверить, что на самом деле люди используют этот прототип! это выпадающее меню только для одного подменю и все !! Я обновил лучшее, которое может иметь два подменю для направления ltr и rtl с поддержкой IE 8.
Fiddle для LTR
Fiddle для RTL
, надеюсь, кто-то найдет это полезным в будущем.
Я также сделал это с помощью jQuery. В моем случае я хотел увидеть немного другого меню (10px). Так что это работает без 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});
});
Надеюсь, это кому-нибудь поможет:)
Это решение использует 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).
Когда я публикую это, уже есть более 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>
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
из 0px (в расширенном состоянии) в -2000px
в свернутом состоянии (аналогично этому ответу ). 2000 здесь - первое магическое число, оно основано на предположении, что ваша коробка не будет выше этой (2000 пикселей кажется разумным выбором).
Использование одного перехода margin-bottom
само по себе имеет две проблемы:
margin-bottom: -2000px
не будет скрывать все - там Будут видны вещи даже в свернутом корпусе. Это небольшое исправление, которое мы сделаем позже. Исправление этой второй проблемы - это то, где вступает второй переход, и этот переход концептуально нацеливается на минимальную высоту оболочки («концептуально», потому что мы на самом деле не используем свойство min-height
для это; об этом позже).
Вот анимация, которая показывает, как объединение перехода нижнего поля с переходом минимальной высоты, одинаковой продолжительности, дает нам комбинированный переход от полной высоты к нулевой высоте, которая имеет одинаковую длительность.
Левая полоса показывает, как отрицательное нижнее поле сдвигает нижнюю часть вверх, уменьшая видимую высоту. Средняя полоса показывает, как минимальная высота гарантирует, что в случае свертывания переход не заканчивается досрочно, а в случае растяжения переход не начинается поздно. Правая полоса показывает, как комбинация этих двух элементов приводит к тому, что окно переходит от полной высоты к нулевой высоте за правильное время.
Для моей демонстрации я установил 50px в качестве верхнего минимального значения высоты. Это второе магическое число, и оно должно быть ниже, чем высота коробки. 50px кажется разумным; кажется маловероятным, что вы очень часто захотите сделать разборный элемент, который даже не достигает 50 пикселей.
Как вы можете видеть на анимации, результирующий переход является непрерывным, но это не дифференцируемо - в момент, когда минимальная высота равна полной высоте, скорректированной по нижнему краю, происходит внезапное изменение скорости. Это очень заметно в анимации, потому что она использует линейную функцию синхронизации для обоих переходов, и потому что весь переход очень медленный. В реальном случае (моя демонстрация вверху) переход занимает всего 300 мс, а переход нижнего поля не является линейным. Я поиграл с множеством различных функций синхронизации для обоих переходов, и те, с которыми я закончил, чувствовали, что они лучше всего работают в самых разных случаях.
Осталось решить две проблемы:
Мы решаем первую проблему, задавая элемент контейнера 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 - ndash; за исключением того факта, что у вас не будет переходов CSS, что делает это довольно бессмысленным упражнением.
Я отправил ответ с некоторым JavaScript и получил downvoted, так раздражался и попробовал еще раз и взломал его с CSS только!
Это решение использует несколько 'методов':
padding-bottom:100%
'взлом', где проценты определяются с точки зрения текущей ширины элемента. [Еще 114] информация об этой технике. результат, хотя то, что мы получаем производительный переход с помощью CSS только и единственной функции перехода для гладкого достижения перехода; Святой Грааль!
, Конечно, существует оборотная сторона! Я не могу разработать, как управлять шириной, в которой содержание отключено (overflow:hidden
); из-за взлома дополнительной нижней части глубоко связаны ширина и высота. Может быть путь, хотя, так возвратится к нему.
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>
Можно, добавив немного несемантических ухищрений. Мой обычный подход - анимировать высоту внешнего DIV, у которого есть единственный дочерний элемент, который является DIV без стиля, используемым только для измерения высоты содержимого.
function growDiv () {var growDiv = document.getElementById ('вырасти'); если (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: высота .5s; -о-переход: высота 0,5 с; -webkit-transition: высота 0,5 с; переход: высота 0,5 с; высота: 0; переполнение: скрыто; контур: сплошной красный 1px; }
Содержимое моего div. Содержимое моего div. Содержимое моего div. Содержимое моего div. Содержимое моего div. Содержимое моего div.
Хотелось бы просто иметь возможность обойтись без .measuringWrapper
и просто установить высоту DIV на auto и анимировать его, но это не так. Похоже, не работает (высота устанавливается, но анимации не происходит).
function growDiv () {var growDiv = document.getElementById ('вырасти'); если (growDiv.clientHeight) {growDiv.style.height = 0; } еще {growDiv.style.height = 'авто'; }}
#grow {-moz-transition: height .5s; -ms-transition: высота .5s; -о-переход: высота 0,5 с; -webkit-transition: высота 0,5 с; переход: высота.5 с; высота: 0; переполнение: скрыто; контур: сплошной красный 1px; }
Содержимое моего div. Содержимое моего div. Содержимое моего div. Содержимое моего div. Содержимое моего div. Содержимое моего div.
Я считаю, что для запуска анимации требуется явная высота. Вы не можете получить анимацию по высоте, если высота (начальная или конечная) равна авто
.
Я хотел сделать, чтобы отделение скользило открытый/близкий не только вертикально, но также и горизонтально, таким образом, оно эффективно скользит открытый от верхнего левого угла до нижнего правого угла. При исследовании я столкнулся с этим вопросом, но ответы являются главным образом обходными решениями и приближениями. Я хотел более точный подход... Наконец я нашел способ сделать это.
В основном мой код ниже достигает этого:
, Таким образом, здесь это:
<style>
.anim { transition: all 2s ease-out; }
#content { background-color: lightgrey; }
</style>
<input type="button" onclick="toggleDiv()" value="Toggle"><br>
<div id="content">
The contents of my div.<br>
The contents of my div. Which could be a bit wider.<br>
The contents of my div. Or could be even a bit more wider.<br>
The contents of my div.<br>
</div>
<script>
function initDiv() {
// put a wrapper around content
var content = document.getElementById("content");
var wrapper = document.createElement("DIV");
// wrapper becomes sibling before content
content.parentNode.insertBefore(wrapper, content);
// put content inside
wrapper.appendChild (content);
// add transition settings through class
wrapper.className = "anim";
wrapper.style.overflow = "hidden";
// make wrapper invisible
wrapper.style.height = 0;
wrapper.style.width = 0;
wrapper.style.display = "none";
// add listener to end of transition of wrapper
wrapper.addEventListener(
"transitionend",
function (e) {
// is it truely a transition on the wrapper, and not on a child in the wrapper or content?
if (e.target == this) {
if (this.style.width == "0px") { // it was the end of closing transition
// set wrapper to not-displayed, so elements are no longer included in the tabIndex (if set)
this.style.display = "none";
} else { // it was the end of opening transition
// put width and height of content to 100% so it responds to window resizes while open
// content is always first and only child
this.children[0].style.width = "100%";
this.children[0].style.height = "100%";
// set overflow-y responsive to window resizing
wrapper.style.overflowY = "auto";
};
};
},
false);
};
function toggleDiv() {
var content = document.getElementById("content");
var wrapper = content.parentNode;
if (wrapper.style.width == "0px") { // triggered from closed state
// set content width to width available to wrapper
content.style.width = wrapper.parentNode.scrollWidth;
// make wrapper visible
wrapper.style.display = "block";
// set the height to the rendered content height
content.style.height = content.scrollHeight;
// adjust transition duration so that it has a more or less constant speed regardless of size of content
wrapper.style.transitionDuration = 0.1 + content.clientHeight/200 + "s";
// set width to maximum avaible and height to rendered content height (triggers transition)
wrapper.style.width = "100%";
wrapper.style.height = content.style.height;
} else { // triggered from opened state
// content width was set to 100% on transitionend. Make it fixed again to the current available width
content.style.width = wrapper.parentNode.scrollWidth;
// same for height, only the rendered content height
content.style.height = content.scrollHeight;
wrapper.style.overflowY = "hidden";
// adjust transition duration again (window -and content- could have been resized)
wrapper.style.transitionDuration = 0.1 + content.clientHeight/200 + "s";
// set wrapper size to zero and trigger transition (triggers transition)
wrapper.style.height = 0;
wrapper.style.width = 0;
};
};
initDiv();
</script>
Я отвечал требованиям никакого JS использование Техники 2: преобразуйте: scaleY () статьи ниже.
https://css-tricks.com/using-css-transitions-auto-dimensions /
.wrapper ul {
transform: scaleY(0);
transform-origin: top;
transition: 0.3s;
height: 0;
}
.wrapper:hover ul {
height: auto;
transform: scaleY(1)
}
<div class="wrapper">
<h2>List</h2>
<ul>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
</ul>
</div>
Я не решаюсь отправлять это, поскольку это не нарушает 'JavaScript' часть вопроса; но сделает так так или иначе, как это расширяется на ответ yScale https://, stackoverflow.com/a/17260048/6691 так мог думаться, поскольку фиксация для "на самом деле не удаляет пространство" проблема с тем ответом с основным масштабным эффектом, все еще работающим, когда JavaScript отключен.
Еще один протест состоит в том, что это не должно использоваться с общим правилом CSS 'при наведении курсора', но должно только использоваться, когда переход инициирован путем добавления класса в JavaScript, в которой точке Вы инициировали бы ограниченное временем выполнение requestAnimationFrame
логика. jsfiddle пример ниже выполнений непрерывно в фоновом режиме в demonsration целях, который не подходит для нормального веб-сайта, где существуют другие вещи, продолжающиеся.
Вот демонстрация: http://jsfiddle.net/EoghanM/oa5dprwL/5/
В основном, мы используем requestAnimationFrame
для контроля результирующей высоты поля после scaleY
, преобразование было применено (el.getBoundingClientRect().height
, получает это), и затем примените отрицание margin-bottom
на элемент для 'съедения' пробела.
Это работает с любым из эффектов преобразования; я добавил rotateX с перспективой демонстрацию также.
я не включал код для поддержания любой существующей граничной нижней части на элементе.