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

Я пытаюсь заставить <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>

Ответы [ 45 ]

26 голосов
/ 26 февраля 2016

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

Нет 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>
23 голосов
/ 05 июля 2016

Было мало упоминаний о свойстве Element.scrollHeight, которое может быть полезно здесь и все еще может использоваться с чистым переходом CSS.Свойство всегда содержит «полную» высоту элемента, независимо от того, переполняется ли его содержимое в результате свернутой высоты (например, height: 0).

Как таковое, для height: 0 (эффективнополностью свернутый элемент), его «нормальная» или «полная» высота все еще легко доступна через его значение scrollHeight (неизменно пиксель длина).

Для такого элемента, если предположить, чтоуже настроен переход, например, например (используя ul в соответствии с исходным вопросом):

ul {
    height: 0;
    transition: height 1s; /* An example transition. */
}

Мы можем запустить желаемое анимированное «увеличение» высоты, используя только CSS, с помощью чего-то вроде следующего (здесьпри условии, что ul переменная ссылается на список):

ul.style.height = ul.scrollHeight + "px";

Вот и все.Если вам нужно свернуть список, подойдет любое из двух следующих утверждений:

ul.style.height = "0";
ul.style.removeProperty("height");

Мой конкретный вариант использования вращался вокруг анимирования списков неизвестной и часто значительной длины, поэтому мне было неудобно выбирать произвольную«достаточно большая» спецификация height или max-height и риск обрезания контента или контента, который вам вдруг понадобится прокрутить (например, overflow: auto).Кроме того, при использовании решений на основе max-height замедление и синхронизация нарушаются, поскольку используемая высота может достичь своего максимального значения намного раньше, чем потребуется для max-height, чтобы достичь 9999px.И с ростом разрешения экрана длина пикселей, например 9999px, оставляет неприятный привкус во рту.Это конкретное решение решает проблему элегантным образом, на мой взгляд.

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

21 голосов
/ 16 октября 2016

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

Solution as Fiddle

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>
17 голосов
/ 02 августа 2015

Хорошо, я думаю, что придумал супер простой ответ ... нет 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>
14 голосов
/ 06 октября 2013

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

11 голосов
/ 10 апреля 2011

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

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}
10 голосов
/ 05 августа 2017

Flexbox Solution

Плюсы:

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

Минусы:

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

То, как это работает, заключается в том, чтобы всегда иметь flex-based: auto для элемента с содержимым, а вместо этого переходить в flex-grow и flex-shrink.

Редактировать: улучшенная JS Fiddle, вдохновленная интерфейсом Xbox One.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  transition: 0.25s;
  font-family: monospace;
}

body {
  margin: 10px 0 0 10px;
}

.box {
  width: 150px;
  height: 150px;
  margin: 0 2px 10px 0;
  background: #2d333b;
  border: solid 10px #20262e;
  overflow: hidden;
  display: inline-flex;
  flex-direction: column;
}

.space {
  flex-basis: 100%;
  flex-grow: 1;
  flex-shrink: 0;    
}

p {
  flex-basis: auto;
  flex-grow: 0;
  flex-shrink: 1;
  background: #20262e;
  padding: 10px;
  width: 100%;
  text-align: left;
  color: white;
}

.box:hover .space {
  flex-grow: 0;
  flex-shrink: 1;
}
  
.box:hover p {
  flex-grow: 1;
  flex-shrink: 0;    
}
<div class="box">
  <div class="space"></div>
  <p>
    Super Metroid Prime Fusion
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Resident Evil 2 Remake
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Yolo The Game
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Final Fantasy 7 Remake + All Additional DLC + Golden Tophat
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    DerpVille
  </p>
</div>

JS Fiddle

9 голосов
/ 19 мая 2015

Мне кажется, я нашел действительно твердое решение

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

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

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

Скрипки!

7 голосов
/ 10 октября 2013

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

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

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

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

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

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

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

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

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

(function(doc){

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

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

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

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

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

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

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

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

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

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

})(document);

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

    document.addEventListener('click', function(e){
      if (e.target.nodeName == 'BUTTON') {
        var next = e.target.nextElementSibling;
        next.hasAttribute('reveal') ? next.removeAttribute('reveal') : next.setAttribute('reveal', '');
      }
    }, false);
7 голосов
/ 17 августа 2013

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

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

$('button').bind('click', function(e) { 
  e.preventDefault();
  w = $('#outer');
  if (w.hasClass('collapsed')) {
    w.css({ "max-height": $('#inner').outerHeight() + 'px' });
  } else {
    w.css({ "max-height": "0px" });
  }
  w.toggleClass('collapsed');
});

Вот ссылка jsfiddle: http://jsfiddle.net/pbatey/duZpT

Вот jsfiddle с абсолютнымминимальное количество кода требуется: http://jsfiddle.net/8ncjjxh8/

...