提问



我试图使用CSS过渡使<ul>向下滑动。


<ul>height: 0;开始。悬停时,高度设置为height:auto;。但是,这导致它只是出现, not 过渡,


如果我从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上的值设置为比您的盒子更大的值。


请参阅Chris Jordan在另一个答案中提供的JSFiddle演示。[145]




#menu #list {
    max-height: 0;
    transition: max-height 0.15s ease-out;
    overflow: hidden;
    background: #d5d5d5;
}

#menu:hover #list {
    max-height: 500px;
    transition: max-height 0.25s ease-in;
}

<div id="menu">
    <a>hover me</a>
    <ul id="list">
        <!-- Create a bunch, or not a bunch, of li's to see the timing. -->
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>



您应该使用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而不是height,http://jsfiddle.net/dotnetCarpenter/7cnfc/206/[147] [148]

最佳参考


当其中一个高度为auto时,你无法在高度上制作动画,你必须设置两个明确的高度。

其它参考1


我一直使用的解决方案是首先淡出,然后缩小font-sizepaddingmargin值。它看起来不像擦拭,但它有效没有静态heightmax-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;
}


工作范例:




/* 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>

Spacing.



你可以用一点点非语义的jiggery-pokery。我通常的做法是设置外部DIV的高度,该外部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>



我知道这是这个问题的三十分之一的答案,但我认为这是值得的,所以这里有。这是一个仅CSS的解决方案,具有以下属性:



  • 开头没有延迟,转换不会提前停止。在两个方向(扩展和折叠),如果在CSS中指定300ms的转换持续时间,则转换需要300ms,句点。/li>
  • 它正在转换实际高度(与transform: scaleY(0)不同),所以如果在可折叠元素之后有内容,它会做正确的事。

  • 虽然(和其他解决方案一样)是魔术数字(比如挑选一个高于你的盒子的长度),如果你的假设结束,这并不是致命的在这种情况下,转换可能看起来并不令人惊讶,但在转换之前和之后,这不是问题:在扩展(height: auto)状态中,整个内容始终具有正确的高度(与例如不同)如果你选择的max-height结果太低了。)在折叠状态下,高度应为零。



演示



这里是一个包含三个可折叠元素的演示,所有这些元素都使用相同的CSS。您可能需要在点击运行代码段后单击完整页面。请注意,JavaScript只会切换collapsed CSS上课,没有涉及的测量。 (你可以使用复选框或:target完成没有任何JavaScript的精确演示。另请注意,负责转换的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>



使用CSS3过渡动画高度的可视化解决方法是为填充设置动画。


你没有完全获得完整的擦除效果,但是使用过渡持续时间和填充值可以让你足够接近。如果你不想明确设置高度/最大高度,这应该是你的意思寻找。


div {
    height: 0;
    overflow: hidden;
    padding: 0 18px;
    -webkit-transition: all .5s ease;
       -moz-transition: all .5s ease;
            transition: all .5s ease;
}
div.animated {
    height: auto;
    padding: 24px 18px;
}


http://jsfiddle.net/catharsis/n5XfG/17/(在jsFiddle之上翻过stephband)[149]

其它参考2


我的解决方法是将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>



接受的答案适用于大多数情况,但是当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>



使用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/[150]

其它参考3


没有硬编码值。


没有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>



正如我发布的那样,已有超过30个答案,但我觉得我的答案在杰克已经接受的答案上有所改善。


我不满足于仅使用max-height和CSS3过渡而产生的问题,因为许多评论者指出,你必须将max-height值设置得非常接近实际高度,否则你将得到一个请参阅此JSFiddle以获取该问题的示例。[152]


为了解决这个问题(虽然仍然没有使用JavaScript),我添加了另一个转换transform: translateY CSS值的HTML元素。


这意味着使用max-heighttranslateY:max-height允许元素按下它下面的元素,而translateY给出我们想要的即时效果。 max-height的问题仍然存在,但其影响有所减轻。
这意味着您可以为max-height值设置更大的高度,并且更少担心它。


总体好处是,在转换回(崩溃)时,用户立即看到translateY动画,因此max-height花费的时间并不重要。


作为小提琴的解决方案 [153]




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>



几乎没有提到Element.scrollHeight属性,它在这里很有用,但仍然可以用于纯CSS过渡。该属性始终包含元素的完整高度,无论其内容是否以及如何因折叠高度而溢出(例如height: 0)。[154]


因此,对于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");


我的特定用例围绕着未知且通常相当长的动画列表,因此我不满意任意足够大heightmax-height规范并冒着截断内容或内容的风险突然需要滚动(如overflow: auto,例如)。此外,基于max-height的解决方案打破了缓和和时间,因为使用的高度可能比max-height达到9999px所需的时间更快达到其最大值。随着屏幕分辨率的增长,像9999px这样的像素长度在我的嘴里留下了不好的味道。在我看来,这个特殊的解决方案以优雅的方式解决了这个问题。


最后,这里希望CSS的未来修订地址作者需要更优雅地完成这些事情 - 重新审视计算与已使用和已解决值的概念,并考虑转换是否应适用于计算值,包括widthheight的转换(目前有一些特殊处理)。

其它参考4


好的,所以我想我想出了一个超级简单的答案......
没有max-height,使用relative定位,在li元素上工作,&是纯CSS。
除了Firefox之外,我还没有测试过任何东西,虽然从CSS来看,它应该适用于所有浏览器。


FIDDLE:http://jsfiddle.net/n5XfG/2596/[155]


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>

其它参考5


您可以从height:0过渡到height:auto,同时提供最小高度和最大高度。


div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}

其它参考6


我认为我提出了一个非常可靠的解决方案


好!我知道这个问题和互联网一样古老但我觉得我有一个解决方案,我把它变成了一个名为突变转换的插件。每当DOM发生变化时,我的解决方案就会为被跟踪元素设置style=""属性。最终的结果是你可以使用好的ole CSS进行转换,而不是使用hacky修复或特殊的javascript。您唯一需要做的就是使用data-mutant-attributes="X"设置要跟踪的元素。 [156]


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


而已!此解决方案使用MutationObserver来跟踪DOM中的更改。因此,您不必设置任何内容或使用javascript手动设置动画。自动跟踪更改。但是,因为它使用MutationObserver,所以只会在IE11 +中进行转换。

小提琴! [157]



  • 演示从height: auto过渡到height: 100%

  • 在添加子时展示过渡height: auto


其它参考7


编辑:向下滚动以获取更新的答案

我正在制作一个下拉列表并看到这个帖子......许多不同的答案,但我也决定分享我的下拉列表,...它不完美,但至少它只会使用css下拉!我我一直在使用transform:translateY(y)将列表转换为视图...

您可以在测试中看到更多内容
http://fiddle.jshell.net/BVEpc/4/

我已将div放在每个li后面,因为我的下拉列表来自并正确显示它们需要,我的div代码是:[158] [159] [160]


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


并悬停是:


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


并且因为ul高度被设置为它可以覆盖你的身体内容的内容,这就是为什么我为ul做了这个:


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


并悬停:


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


转换后的第二次是延迟,并且在我的下拉列表被动关闭后它将被隐藏......

希望以后有人能从中受益。



编辑:我只是不相信人们实际上使用这个原型!这个下拉菜单只适用于一个子菜单,而这一切都是!!
我已经更新了一个更好的,可以在IE 8支持下为ltr和rtl方向提供两个子菜单。

小提琴LTR

RTL的小提琴

希望有人在将来发现这个有用。[161] [162]

其它参考8


这里是从任何起始高度(包括0)过渡到自动(完整大小和灵活)的方式,无需每个节点的硬件代码或任何初始化的用户代码:https://github.com/csuwildcat/transition-auto。这基本上是你想要的圣杯 - 我相信 - > http://codepen.io/csuwldcat/pen/kwsdF。只需将以下JS文件打入你的页面,你需要的一切之后要做的是添加/删除一个布尔属性 - reveal="" - 来自你想要展开和收缩的节点。[163] [164]


在您包含示例代码下方的代码块后,您需要以用户身份完成所有操作:


/*** 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™


/ *高度代码:auto;过渡* /


(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);

其它参考9


杰克对最大高度动画的回答非常好,但我发现设置一个大的最大高度令人烦恼的延迟。


可以将可折叠内容移动到内部div中,并通过获取内部div的高度来计算最大高度(通过JQuery,它可以是outerHeight())。


$('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 [165]


这里有一个绝对最少的代码量的jsfiddle:http://jsfiddle.net/8ncjjxh8/[166]

其它参考10


Flexbox解决方案


优点:



  • 简单

  • 没有JS

  • 平稳过渡



缺点:



  • 元素需要放在固定高度的flex容器中



它的工作方式是始终使用flex-basis:对包含内容的元素执行auto,然后转换flex-grow和flex-shrink。


编辑:改进的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>



我意识到这个线程已经老了,但它在某些谷歌搜索中排名很高,所以我觉得值得更新。


你也可以获得/设置元素的高度:


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


您应该在内联脚本标记中的target_box的结束标记之后立即转储此Javascript。

其它参考11


这是我刚刚与jQuery结合使用的解决方案。这适用于以下HTML结构:


<nav id="main-nav">
    <ul>
        <li>
            <a class="main-link" href="yourlink.html">Link</a>
            <ul>
                <li><a href="yourlink.html">Sub Link</a></li>
            </ul>
        </li>
    </ul>
</nav>


和功能:


    $('#main-nav li ul').each(function(){
        $me = $(this);

        //Count the number of li elements in this UL
        var liCount = $me.find('li').size(),
        //Multiply the liCount by the height + the margin on each li
            ulHeight = liCount * 28;

        //Store height in the data-height attribute in the UL
        $me.attr("data-height", ulHeight);
    });


然后,您可以使用单击功能使用css()设置和删除高度


$('#main-nav li a.main-link').click(function(){
    //Collapse all submenus back to 0
    $('#main-nav li ul').removeAttr('style');

    $(this).parent().addClass('current');

    //Set height on current submenu to it's height
    var $currentUl = $('li.current ul'),
        currentUlHeight = $currentUl.attr('data-height');
})


CSS:


#main-nav li ul { 
    height: 0;
    position: relative;
    overflow: hidden;
    opacity: 0; 
    filter: alpha(opacity=0); 
    -ms-filter: "alpha(opacity=0)";
    -khtml-opacity: 0; 
    -moz-opacity: 0;
    -webkit-transition: all .6s ease-in-out;
    -moz-transition: all .6s ease-in-out;
    -o-transition: all .6s ease-in-out;
    -ms-transition: all .6s ease-in-out;
    transition: all .6s ease-in-out;
}

#main-nav li.current ul {
    opacity: 1.0; 
    filter: alpha(opacity=100); 
    -ms-filter: "alpha(opacity=100)";
    -khtml-opacity: 1.0; 
    -moz-opacity: 1.0;
}

.ie #main-nav li.current ul { height: auto !important }

#main-nav li { height: 25px; display: block; margin-bottom: 3px }

其它参考12


扩展@jake的答案,过渡将一直到最大高度值,导致极快的动画 - 如果你设置两者的过渡:悬停和关闭,你可以更多地控制疯狂的速度。


所以li:hover是当鼠标进入状态然后非hovered属性的转换将是鼠标离开。


希望这会有所帮助。


例如:


.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/[167]

其它参考13


我能够做到这一点。我有.child&一个.parent div。子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 */
}


您可以在.parentpx%中指定height,或保留为auto。然后这个div在向下滑动时屏蔽.child div。

其它参考14


我最近在li元素上过渡max-height而不是包裹ul


理由是,与大max-heights相比,小max-heights的延迟远不那么明显(如果有的话),我也可以设置max-height相对于font-size的值font-size]] li而不是使用emsrems的任意大数字。


如果我的字体大小是1rem,我会将max-height设置为3rem之类的东西(以容纳包装的文本)。你可以在这里看到一个例子:


http://codepen.io/mindfullsilence/pen/DtzjE[168]

其它参考15


我没有详细阅读所有内容,但最近我遇到了这个问题,我做了以下事情:


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,它首先显示高达200px高度的内容,并且在悬停时它的大小至少与div的整个内容一样高.Div不会变成3000px但是3000px是我的限制确保在non:hover上进行转换,否则你可能会得到一些奇怪的渲染。这样:hover继承自non:hover。


转换不起作用从px到%或auto。您需要使用相同的度量单位。
这对我来说很好。使用HTML5使其完美....


请记住,总有一种解决方法......; )


希望有人觉得这很有用

其它参考16


将高度设置为自动并转换最大高度。


在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%; /**/
}

其它参考17


如果硬编码,Jake的最大高度解决方案效果很好
提供的最大高度值不比实际高度大很多
(因为否则会出现不良延迟和时间问题)。
另一方面,如果硬编码值是意外的
不超过真正的高度,元素不会完全打开。


以下仅CSS解决方案还需要硬编码大小
应该大于大多数发生的实际尺寸。不过这个
如果实际大小在某些情况下大于,则解决方案也有效
硬编码的大小。在那种情况下,过渡可能会跳跃一点,
但它永远不会留下部分可见的元素。
因此,该解决方案也可以用于未知内容,例如从
一个数据库,你只知道内容通常不大
比x像素,但也有例外。


想法是使用负值为margin-bottom(或margin-top为a
稍微不同的动画)并将内容元素放入一个
溢出的中间元素:隐藏。内容的负边际
元素因此降低了中间元素的高度。


以下代码使用从-150px到的margin-bottom的转换
0像素。只要内容元素不是这样,这一点就可以正常工作
高于150px。此外,它使用最大高度的过渡
中间元素从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>


保证金底部的价值应为负数且尽可能接近
可能到内容元素的实际高度。如果它(s absoute
值)更大,有类似的延迟和时序问题
最大高度解决方案,然而可以限制,只要
硬编码大小并不比真实大小大。如果是绝对的
margin-bottom的值小于实际高度
tansition跳了一下。在任何情况下过渡后
内容元素要么完全显示,要么完全删除。


有关详细信息,请参阅我的博客文章http://www.taccgl.org/blog/css_transition_display.html#combined_height [169]

其它参考18


这不是解决问题的解决方案,而是更多的解决方法。它只能用文本编写,但可以根据需要更改为与其他元素一起使用我确定。


.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 [170]


基本上,您将font-size设置为0并以足够快的速度转换而不是height,max-height或scaleY()等,以获得转换为您想要的高度。要将CSS的实际高度转换为auto当前不可能,但是转换内部的内容,因此是字体大小的转换。



  • 注意 - 在codepen中有javascript,但它的唯一目的是为手风琴点击添加/删除css类。这可以通过隐藏的单选按钮来完成,但我并不专注于此,只是高度转换。


其它参考19


这是我经常遇到的问题


http://jsfiddle.net/ipeshev/d1dfr0jz/[171]


尝试将关闭状态的延迟设置为某个负数,并使用该值稍微调整一下。你会看到迪它几乎可以说是人眼;)。


它适用于主流浏览器,但对我来说足够好。
这很奇怪但是会给出一些结果。


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

button:hover ~ .expandable {
    max-height: 9000px;
    transition: all 1s ease-in-out;
}