题 我怎样才能过渡高度:0;高度:自动;用CSS?


我想做一个 <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>


1602
2017-08-18 02:50


起源


我相信 height:auto/max-height 解决方案只有在扩展区域大于的情况下才有效 height 你想限制。如果你有 max-height 的 300px,但组合框下拉列表,可以返回 50px, 然后 max-height 对你不会有帮助 50px 是根据元素的数量变化,你可以到达一个我无法修复它的不可能的情况,因为 height 不固定, height:auto 是解决方案,但我不能使用转换。 - Christopher Thomas
OP正在尝试使用css解决方案,而不是js,否则他们只能使用溢出和动画 - Toni Leigh
@ToniLeigh或jQuery.slideToggle(); - mopo922
所有这些答案都不是很“正确”....我有一个解决方案(今天补充说明)只有两个CSS声明。它不使用max-height。这是纯CSS,设置起来非常简单。适用于相对定位。这是一个小提琴 jsfiddle.net/n5XfG/2596 - VIDesignz
@VIDesignz:但内部div的-100%margin-top收到了 宽度 包装div的 不是高度。 所以这个解决方案有同样的问题,即最大高度解决方案。此外,当宽度小于内容的高度时,并非所有内容都被-100%margin-top隐藏。所以这是一个错误的解决方案。 - GregTom


答案:


使用 max-height 在转型而不是 height。并设置一个值 max-height 比你的盒子更大的东西将永远得到。

看到 JSFiddle演示 克里斯乔丹在另一个提供 回答 这里。

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

#menu:hover #list {
    max-height: 500px;
    transition: max-height 0.25s ease-in;
}
<div id="menu">
    <a>hover me</a>
    <ul id="list">
        <!-- Create a bunch, or not a bunch, of li's to see the timing. -->
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>


2161
2017-11-30 18:42



这很棒!除了开始时有一个延迟,因为它开始的最大高度最初是非常高的......嗯,我觉得这有点烦人 - vsync
+1好的解决方案!计算转换的速度计算为您指定转换到最大高度值的时间...但由于高度将小于最大高度,因此过渡到实际高度的速度将比(通常显着的)高于时间指定。 - kingjeffrey
请注意,当您必须使用远大于实际计算值的值时,这可能会导致丑陋的转换结束。我注意到这一点,同时试图使div从0高度增长到内容高度,因屏幕尺寸不同而变化很大(我的2560x1440显示器上的2行与智能手机上的10行)。为此,我最终选择了js。 - jpeltoniemi
伟大的工作 - 不解决;) - acSlater
这是一个非常懒惰的解决方案。我假设OP想要使用height:auto,因为容器的扩展高度有些不可预测。此解决方案将在动画变为可见之前导致延迟。此外,动画的可见持续时间将是不可预测的。通过计算每个容器子节点的组合高度,然后缓和到精确的高度值,您将获得更可预测(并且可能更平滑)的结果。 - Shawn Whinnery


您应该使用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/


228
2018-06-23 10:57



我正在推荐这个答案,因为它在支持css3-transition的浏览器中运行良好,但应该注意这一点 在IE <9中根本不起作用,和 在IE <10中不会被动画(它会跳跃) - Hailwood
该方法仅部分地实现了期望的效果,但实际上并未实现 去掉 空间。变换后的盒子就像一个相对定位的元素 - 无论它如何缩放,空间都被占用。查看 这个jsFiddle 这需要你的第一个,只是在底部添加一些虚假文本。请注意当框高度缩放为零时,它下方的文本不会向上移动。 - animuson♦
现在它确实: jsfiddle.net/gNDX3/1 基本上你需要根据你的需要设计元素的样式。 CSS / HTML中没有银弹或类似小部件的行为。 - dotnetCarpenter
虽然我赞赏有人尝试不同的方法,但这个解决方案带来的真实效果和复杂性远远超过已经糟糕的最大高度黑客。请不要使用。 - mystrdat
间距失败 jsfiddle.net/PhyQc/336 - e-info128


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


164
2017-08-18 12:46



通常有多种方法可以解决问题,并非所有问题都适用或可能。我不知道为什么@JedidiahHurt和Ryan Ore试图在问答网站上限制可能的答案。特别是考虑到这个答案首先在这里。因为接受的答案是一种解决方法。 - Hooray Im Helping
@jake的答案既不优雅也不正确。这里的相关答案要好得多。它可以正常工作并处理所有大小的情况 - 也不能说接受的答案。 - GraphicsMuncher
这改变了吗?在较少用于折叠的bootstrap中,我看到它们明确地转换了高度,据我所知它适应任何高度: .collapsing { position: relative; height: 0; overflow: hidden; .transition-property(~"height, visibility"); .transition-duration(.35s); .transition-timing-function(ease); } - Andy
哦,你知道,我打赌bootstrap只是在触发CSS动画之前计算并设置内容的高度...... - Andy
是的,确实如此 this.$element[dimension](this.$element[dimension]())[0].offsetHeight - Andy


我一直使用的解决方案是首先淡出,然后缩小 font-sizepadding 和 margin 值。它看起来与擦除不一样,但它没有静电 height 要么 max-height

/* final display */
.menu .list {
    margin: .5em 1em;
    padding: 1em;
}

/* hide */
.menu:not(:hover) .list {
    font-size: 0;
    margin: 0;
    opacity: 0;
    padding: 0;
    /* fade out, then shrink */
    transition: opacity .25s,
                font-size .5s .25s,
                margin .5s .25s,
                padding .5s .25s;
}

/* reveal */
.menu:hover .list {
    /* unshrink, then fade in */
    transition: font-size .25s,
                margin .25s,
                padding .25s,
                opacity .5s .25s;
}

工作范例:

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


81
2018-05-29 14:05



为我整洁地工作。不太像jQuery slideUp / Down。您可以看到只有弱CPU(如旧计算机或移动设备)的差异,同时打开和关闭其中的许多CPU。 - Cruz Nunez
如果你有按钮或任何其他非文本元素,你最终会有不需要的空格,而不是悬停。 - Dennis W
您可以通过选择所有子元素来进一步细化它 * 并应用其他更改。但是,按钮应该受到上述代码的影响,如果它们的样式正确的话 em。 - Steven Vachon
在我的情况下,我还需要添加 line-height: 0; 和 border-width: 0; - Andrey Shatilov
你不应该调整 line-height 如果你正确地避免了值的单位: developer.mozilla.org/en-US/docs/Web/CSS/... - Steven Vachon


你可以用一点点非语义的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>

人们希望能够免除 .measuringWrapper 并且只是将DIV的高度设置为auto并具有该动画,但这似乎不起作用(高度设置,但没有动画发生)。

function growDiv() {
  var growDiv = document.getElementById('grow');
  if (growDiv.clientHeight) {
    growDiv.style.height = 0;
  } else {
    growDiv.style.height = 'auto';
  }
}
#grow {
  -moz-transition: height .5s;
  -ms-transition: height .5s;
  -o-transition: height .5s;
  -webkit-transition: height .5s;
  transition: height .5s;
  height: 0;
  overflow: hidden;
  outline: 1px solid red;
}
<input type="button" onclick="growDiv()" value="grow">
<div id='grow'>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
  <div>
    The contents of my div.
  </div>
</div>

我的解释是动画运行需要一个显式高度。任何高度(起始高度或结束高度)都不能在高度上获得动画 auto


64
2018-06-30 13:32



由于这依赖于javascript,你也可以使用javascript轻松添加measurementWrapper! - Quickredfox
你可以在没有包装的情况下完成。只是:function growDiv(){var growDiv = document.getElementById('grow'); if(growDiv.clientHeight){growDiv.style.height = 0; } else {growDiv.style.height = growDiv.scrollHeight +'px'; }} - user1742529
看看这个...谈谈一个简单的答案 jsfiddle.net/n5XfG/2596 ......没有充分理由,你的答案非常复杂。没必要 max-height,没必要 auto,尤其不需要Javascript !!只是两个简单的声明 - VIDesignz
@VIDesignz你动态超过保证金:100%。这是100%的 宽度 元素,而不是它的高度!这意味着,如果您的元素的高度大于宽度,则不会隐藏它。而且, 实际 动画速度与定义的速度完全不同。 - Timo Türschmann
在我阅读更多有关蒂莫的评论之前,我对VIDesignz的答案感到很兴奋。是, margin-top (和 margin-bottom)当以百分比定义时相对于宽度,是的,这是愚蠢的,但它也解释了为什么开放和关闭动画时序完全不同 - 这与你在最高评级答案中看到的相同,指定硬编码的最大值高度。为什么这么难做对吗? - Coderer


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

  • 开始时没有延迟,过渡不会提前停止。在两个方向(展开和折叠)中,如果在CSS中指定300毫秒的转换持续时间,则转换需要300毫秒(周期)。
  • 它正在过渡实际高度(不像 transform: scaleY(0)),如果在可折叠元素之后有内容,它会做正确的事情。
  • 虽然(像在其他解决方案中)那里  神奇的数字(比如“挑选一个高于你的盒子的长度”),如果你的假设最终错了,那就不是致命的。在这种情况下,过渡可能看起来并不令人惊讶,但在过渡之前和之后,这不是问题:在扩展中(height: auto)状态,整个内容总是具有正确的高度(例如,如果你选择一个 max-height结果证明太低了。在崩溃的状态下,高度应该是零。

演示

这是一个包含三个可折叠元素的演示,所有元素都使用相同的CSS。单击“运行代码段”后,您可能需要单击“完整页面”。请注意,JavaScript只会切换 collapsed CSS类,没有涉及测量。 (你可以通过使用复选框或完成这个完全没有任何JavaScript的演示 :target)。另请注意,负责转换的CSS部分非常短,而HTML只需要一个额外的包装元素。

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

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

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


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

  
}

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

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

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

<div id="container">
  <div class="menu">
    <div class="menu-item">Something involving a holodeck</div>
    <div class="menu-item">Send an away team</div>
    <div class="menu-item toggler">Advanced solutions</div>
    <div class="collapsible-wrapper collapsed">
      <div class="collapsible">
        <div class="menu-item">Separate saucer</div>
        <div class="menu-item">Send an away team that includes the captain (despite Riker'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 过渡本身有两个问题:

  • 如果你实际上有一个高于2000像素的盒子,那么a margin-bottom: -2000px 不会隐藏一切 - 即使在倒塌的情况下也会有可见的东西。这是一个小修复,我们稍后会做。
  • 如果实际的盒子是1000像素高,而你的过渡是300ms长,那么 可见 在大约150ms之后过渡已经结束(或者,相反的方向,开始晚150ms)。

修复第二个问题是第二个转换的来源,这个转换在概念上以包装器为目标 最低限度 身高(“概念上”,因为我们实际上并没有使用 min-height 财产;以后更多内容)。

这是一个动画,显示了如何将底部边缘过渡与最小高度过渡相结合,两者具有相同的持续时间,为我们提供了从全高度到零高度的组合过渡,具有相同的持续时间。

animation as described above

左侧栏显示负底部边缘如何向下推动底部,降低可见高度。中间栏显示最小高度如何确保在折叠情况下,过渡不会提前结束,并且在扩展的情况下,过渡不会延迟。右侧栏显示两者的组合如何使盒子在正确的时间内从全高度过渡到零高度。

对于我的演示,我已经确定50px作为最小高度值的上限。这是第二个神奇的数字,它应该低于盒子的高度。 50px似乎也是合理的;你似乎不太可能经常想要制作一个可折叠的元素,它首先不是50像素高。

正如您在动画中看到的那样,所产生的过渡是连续的,但它是不可区分的 - 当最小高度等于由下边距调整的全高时,速度会突然改变。这在动画中非常明显,因为它对两个过渡使用线性定时功能,并且因为整个过渡非常慢。在实际情况下(我的演示在顶部),转换只需要300毫秒,底部边距转换不是线性的。我已经为这两种转换玩了很多不同的计时功能,而我最终感觉它们最适合各种各样的情况。

还有两个问题需要解决:

  1. 从上面开始,高度超过2000像素的盒子在折叠状态下没有完全隐藏,
  2. 和相反的问题,在非隐藏的情况下,即使转换未运行,高度小于50像素的框也太高,因为最小高度使它们保持在50像素。

我们通过给出容器元素a来解决第一个问题 max-height: 0 在倒塌的情况下,用 0s 0.3s 过渡。这意味着它不是真正的过渡,而是 max-height 适用延迟;它只适用于转换结束后。为了使其正常工作,我们还需要选择一个数字 max-height 对于相反的,没有崩溃的州。但与2000px的情况不同,选择太大的数字会影响转换的质量,在这种情况下,它确实无关紧要。所以我们可以选择一个比我们高的数字 知道 没有高度会接近这一点。我选了一百万像素。如果您觉得可能需要支持高度超过一百万像素的内容,那么1)对不起,2)只需添加几个零。

第二个问题是我们实际上没有使用的原因 min-height 最小高度过渡。相反,有一个 ::after 带有a的容器中的伪元素 height 从50px过渡到零。这与a具有相同的效果 min-height:它不会让容器缩小到伪元素当前所具有的任何高度。但是因为我们正在使用 height不是 min-height,我们现在可以使用 max-height (再次应用延迟)一旦转换结束,将伪元素的实际高度设置为零,确保至少在转换之外,即使是小元素也具有正确的高度。因为 min-height 是  比 max-height,如果我们使用容器,这将无法工作 min-height 而不是伪元素 height。就像 max-height 在前一段中,这个 max-height 还需要一个转换另一端的值。但在这种情况下,我们可以选择50px。

测试过Chrome(Win,Mac,Android,iOS),Firefox(Win,Mac,Android),Edge,IE11(除了我的演示中的flexbox布局问题,我没有打扰调试)和Safari(Mac,iOS) )。说到flexbox,应该可以在不使用任何flexbox的情况下完成这项工作;事实上,我认为你几乎可以使所有东西都在IE7中工作 - 除了你不会有CSS过渡这一事实,这使得它成为一个毫无意义的练习。


45
2018-05-14 14:33



我希望你能缩短(简化)你的解决方案,或至少代码示例 - 看起来90%的代码示例与你的答案无关。 - Gil Epshtain


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

你没有完全获得完整的擦除效果,但是使用transition-duration和padding值可以让你足够接近。如果您不想明确设置height / max-height,那么这应该是您正在寻找的。

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)


44
2018-06-26 19:05



我认为这是最好的答案。这种技术也可以扩展到调整孩子的填充。在我的情况下,我能够将它与显示的一些内容的显式高度转换相结合,并且总效果比最大高度解决方案更成功,这对于揭示是好的但是引入了一个尴尬的时刻延迟隐藏。我很快就没有动画了,而是引入了毫无意义的延迟,使我的应用程序看起来没有反应。我很惊讶很多人似乎认为这是可以接受的。 - Semicolon
除了这里,你根本没有动画高度。你正在为填充设置动画...它可以消失得很好,因为它可以从当前状态动画到0,但如果你仔细观察它扩展它会弹出文本然后填充只会动画..因为它没有我不知道如何从0动画到自动....它需要一个数值范围......这就是补间如何运作。 - Rob R
这是一个很好的解决方法,而不是hacky。这不是最好的答案 这个 问题,但这是一个对我有用的替代方案。有时你只需要一些高度动画的效果,而不是完整的动画:) - Ivan Durst
使用转换延迟时,此解决方案也会失败。 - Michel Joanisse
我也同意这个解决方案是一个干净的解决方案,如果你的动画足够快就能提供非常流畅的转换(在我的情况下,对于转换为0.1s的手风琴来说它是完美的!)。虽然它不会包含很多应用程序,但其他问题也不会出现在这个问题上! - Remi D


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


43
2018-03-19 00:44



@ Derija93那是使用普通的旧javascript超时动画。挑战是使用CSS3过渡。 - Adam
嗯,是。但是,为什么你会使用“CSS3过渡”,如果你在你的例子中已经使用了jQuery,一个库,它提供了很多“少写,做多”的代码呢?我想指出你的版本可能看起来好多了,即使它更复杂,如果它不使用jQuery,所以它可以在几乎任何网站上运行。我想我措辞错了。抱歉'回合那个。 ;) - Kiruse
@ Derija93也许是因为CSS3过渡(根据我能找到的所有来源)比jQuery动画好得多。 (实际上对于我目前的用例非常重要,这使我来到这里。) - Mark Amery
@ Derija93'原因与CSS3过渡相比,Javascript动画运行缓慢,而使用jQuery动画,您必须担心动画循环。单击动画,然后快速单击并观看动画重复。这是用CSS3处理的。 - Dropped.on.Caprica
@ Dropped.on.Caprica现在有点老了。我已经说过,我误解了他试图展示的概念。无论如何,对于简单的动画, .stop 为相当复杂的动画循环问题做了诀窍。现在,当你为高度和颜色设置动画但希望仅中断高度动画时,事情变得有点棘手...我明白你的观点。 - Kiruse