2548

我正在尝试<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>

4

60 回答 60

3275

max-height在过渡中使用而不是height. max-height并为比您的盒子更大的东西设置一个值。

请参阅Chris Jordan 在此处的另一个答案中提供的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>

于 2011-11-30T18:42:56.333 回答
404

您应该改用 scaleY 。

ul {
  background-color: #eee;
  transform: scaleY(0);    
  transform-origin: top;
  transition: transform 0.26s ease;
}
p:hover ~ ul {
  transform: scaleY(1);
}
<p>Hover This</p>
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>

我在jsfiddle上制作了上述代码的供应商前缀版本,并将您的jsfiddle更改为使用 scaleY 而不是 height。

编辑 有些人不喜欢如何scaleY转换内容。如果这是一个问题,那么我建议使用clip

ul {
  clip: rect(auto, auto, 0, auto);
  position: absolute;
  margin: -1rem 0;
  padding: .5rem;

  color: white;

  background-color: rgba(0, 0, 0, 0.8);

  transition-property: clip;
  transition-duration: 0.5s;
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
h3:hover ~ ul,
h3:active ~ ul,
ul:hover {
  clip: rect(auto, auto, 10rem, auto);
}
<h3>Hover here</h3>
<ul>
  <li>This list</li>
  <li>is clipped.</li>
  <li>A clip transition</li>
  <li>will show it</li>
</ul>
<p>
  Some text...
</p>

于 2013-06-23T10:57:44.443 回答
248

当涉及的高度之一是 时,您当前无法在高度上设置动画auto,您必须设置两个显式高度。

于 2010-08-18T12:46:30.280 回答
161

我一直使用的解决方案是先淡出,然后缩小font-size,paddingmargin值。它看起来与擦拭物不同,但它可以在没有静态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;
}
<div id="menu">
    <b>hover me</b>
    <ul id="list">
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>

<p>Another paragraph...</p>

于 2015-05-29T14:05:06.680 回答
133

这是具有以下属性的纯 CSS解决方案:

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

演示

这是一个包含三个高度不同的可折叠元素的演示,它们都使用相同的 CSS。单击“运行片段”后,您可能希望单击“整页”。请注意,JavaScript 仅切换collapsedCSS 类,不涉及测量。: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-bottom0px(处于展开状态)转换-2000px为折叠状态(类似于此答案)。这里的 2000 是第一个幻数,它基于您的框不会高于此的假设(2000 像素似乎是一个合理的选择)。

单独使用margin-bottom转换本身有两个问题:

  • 如果您实际上有一个高于 2000 像素的盒子,那么 amargin-bottom: -2000px不会隐藏所有内容——即使在折叠的盒子中也会有可见的东西。这是我们稍后会做的一个小修复。
  • 如果实际的盒子是 1000 像素高,而你的过渡是 300 毫秒长,那么可见过渡在大约 150 毫秒后就已经结束(或者,在相反的方向,开始晚 150 毫秒)。

解决第二个问题是第二个转换出现的地方,这个转换在概念上针对包装器的最小高度(“概念上”,因为我们实际上并没有为此使用该min-height属性;稍后会详细介绍)。

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

如上所述的动画

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

对于我的演示,我已将 50px 作为最小高度值上限。这是第二个幻数,它应该低于盒子的高度。50px 似乎也很合理;您似乎不太可能经常想要使一个最初甚至不到 50 像素高的可折叠元素。

正如您在动画中看到的那样,产生的过渡是连续的,但不可微分——在最小高度等于底部边距调整的全高的那一刻,速度突然发生变化。这在动画中非常明显,因为它对两个过渡都使用了线性计时函数,并且因为整个过渡非常慢。在实际情况下(我的演示在顶部),过渡只需要 300ms,底部边距过渡不是线性的。我已经为这两种过渡使用了许多不同的计时功能,而我最终得到的那些感觉它们在最广泛的情况下效果最好。

还有两个问题需要解决:

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

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

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

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

于 2017-05-14T14:33:47.040 回答
106

你可以,用一点非语义的猜谜扑克。我常用的方法是为具有单个子元素的外部 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.

于 2010-06-30T13:32:08.297 回答
57

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

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

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 的内容)

于 2011-06-26T19:05:31.843 回答
56

接受的答案适用于大多数情况,但是当您的高度变化很大时它就不能很好地工作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>

于 2014-10-20T22:57:21.293 回答
50

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

于 2012-03-19T00:44:51.497 回答
48

几乎没有提到Element.prototype.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");

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

最后,希望未来的 CSS 版本能够解决作者需要更优雅地做这些事情——重新审视“计算”与“使用”和“已解决”值的概念,并考虑转换是否应该适用于计算值,包括带有widthand的转换height(目前得到了一些特殊处理)。

于 2016-07-05T18:59:40.897 回答
39

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/

于 2014-12-16T23:35:42.367 回答
35

没有硬编码值。

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

于 2016-02-26T17:19:20.220 回答
26

当我发布这篇文章时,已经有 30 多个答案,但我觉得我的答案比杰克已经接受的答案有所改进。

我不满足于简单地使用max-height和 CSS3 过渡所产生的问题,因为正如许多评论者所指出的,你必须将你的max-height值设置为非常接近实际高度,否则你会得到延迟。有关该问题的示例,请参阅此JSFiddle 。

为了解决这个问题(仍然不使用 JavaScript),我添加了另一个 HTML 元素来转换transform: translateYCSS 值。

这意味着同时使用max-heighttranslateYmax-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>

于 2016-10-16T16:55:27.853 回答
20

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

小提琴: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>
于 2015-08-01T22:35:00.477 回答
17

根据MDN Web Docs,值已被有意从 CSS 转换规范中排除,因此在 grid 和 flex 布局中auto代替height: auto, use height: 100%,top或property 。flex

展开/折叠覆盖

.grid-container {
  display: grid;
  position: absolute;
}

.content {
  background: aqua;
  height: 0;
  overflow: hidden;
  transition: 1s;
}

span:hover + .grid-container .content {
  height: 100%;
}
<span>Hover over me!</span>

<div class="grid-container">

  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

</div>

<p>Rest of the page content...</p>

展开/折叠滑动覆盖

.grid-container {
  display: grid;
  position: absolute;
  overflow: hidden;
  pointer-events: none; /* to enable interaction with elements below the container */
}

.content {
  background: aqua;
  pointer-events: auto;
  position: relative;
  top: -100%;
  transition: 1s;
}

span:hover + .grid-container .content {
  top: 0;
}
<span>Hover over me!</span>

<div class="grid-container">

  <div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

</div>

<p>Rest of the page content...</p>

在文档流中展开/折叠

html {
  display: grid;
}

body {
  display: flex;
  flex-direction: column;
}

.content {
  background: aqua;
  flex-basis: 0;
  overflow: hidden;
  transition: 1s;
}

span:hover + .content {
  flex: 1;
}
<span>Hover over me!</span>

<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

<p>Rest of the page content...</p>

于 2021-11-07T09:49:53.287 回答
16

编辑:向下滚动以获取更新
答案落下!我一直在使用 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 这样做的原因:

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

并悬停:

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

过渡后的第二次是延迟,它会在我的下拉列表被动画关闭后被隐藏......
希望以后有人能从中受益。

编辑:我简直不敢相信 ppl 真的在使用这个原型!此下拉菜单仅适用于一个子菜单,仅此而已!我更新了一个更好的菜单,它可以有两个子菜单,用于 ltr 和 rtl 方向,并支持 IE 8。
Fiddle for LTR
Fiddle for RTL
希望将来有人会发现这很有用。

于 2013-10-06T10:34:14.987 回答
12

您可以从 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;
}
于 2011-04-10T11:36:00.980 回答
11

弹性盒解决方案

优点:

  • 简单的
  • 没有JS
  • 平稳过渡

缺点:

  • 元素需要放在一个固定高度的弹性容器中

它的工作方式是始终在具有内容的元素上使用 flex-basis: auto ,并转换为 flex-grow 和 flex-shrink 。

编辑:受 Xbox One 界面启发的改进的 JS Fiddle。

* {
  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小提琴

于 2017-08-04T21:01:19.243 回答
9

一句话解决方案:使用 padding transition。对于大多数情况(例如手风琴)来说已经足够了,甚至更好,因为它的速度很快,因为填充值通常不大。

如果您希望动画过程更好,只需提高填充值即可。

.parent{ border-top: #999 1px solid;}
h1{ margin: .5rem; font-size: 1.3rem}
.children {
  height: 0;
  overflow: hidden;
  background-color: #dedede;
  transition: padding .2s ease-in-out, opacity .2s ease-in-out;
  padding: 0 .5rem;
  opacity: 0;
}
.children::before, .children::after{ content: "";display: block;}
.children::before{ margin-top: -2rem;}
.children::after{ margin-bottom: -2rem;}
.parent:hover .children {
  height: auto;
  opacity: 1;
  padding: 2.5rem .5rem;/* 0.5 + abs(-2), make sure it's less than expected min-height */
}
<div class="parent">
  <h1>Hover me</h1>
  <div class="children">Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>
<div class="parent">
  <h1>Hover me(long content)</h1>
  <div class="children">Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>
  </div>
</div>
<div class="parent">
  <h1>Hover me(short content)</h1>
  <div class="children">Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>

于 2020-04-15T05:37:33.037 回答
8

扩展@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/

于 2013-07-09T16:14:52.510 回答
8

该解决方案使用了一些技术:

结果是我们只使用 CSS 获得了高性能的过渡,以及一个平滑的过渡函数来实现过渡;圣杯!

当然,也有缺点!我不知道如何控制内容被截断的宽度(overflow:hidden);由于 padding-bottom hack,宽度和高度密切相关。不过可能有办法,所以会回到它。

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>

于 2019-11-08T18:10:05.393 回答
6

我最近一直在转换max-heightonli元素而不是 wrapping ul

原因是 small 的延迟max-heights与 large 相比远不那么明显(如果有的话)max-heights,我还可以通过使用or来设置max-height相对于 thefont-size的值li而不是某个任意大数的值。emsrems

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

http://codepen.io/mindfullsilence/pen/DtzjE

于 2014-05-12T20:00:38.903 回答
6

我理解这个问题要求没有 JavaScript 的解决方案。但对于那些感兴趣的人来说,这是我使用一点 JS 的解决方案。

好的,所以默认情况下高度会改变的元素的css设置为height: 0;and when open height: auto;。它也有transition: height .25s ease-out;。但当然问题是它不会过渡到或从height: auto;

所以我所做的是在打开或关闭时将高度设置为scrollHeight元素的属性。这种新的内联样式将具有更高的特异性,并覆盖height: auto;height: 0;和过渡运行。

打开时,我添加了一个transitionend事件侦听器,它只运行一次,然后删除内联样式,将其设置回height: auto;允许元素在必要时调整大小,如这个带有子菜单的更复杂示例https://codepen.io/ninjabonsai/笔/GzYyVe

关闭时,我在下一个事件循环周期后立即使用 setTimeout 删除内联样式,没有延迟。这意味着height: auto;暂时被覆盖,允许转换回height 0;

const showHideElement = (element, open) => {
  element.style.height = element.scrollHeight + 'px';
  element.classList.toggle('open', open);

  if (open) {
    element.addEventListener('transitionend', () => {
      element.style.removeProperty('height');
    }, {
      once: true
    });
  } else {
    window.setTimeout(() => {
      element.style.removeProperty('height');
    });
  }
}

const menu = document.body.querySelector('#menu');
const list = document.body.querySelector('#menu > ul')

menu.addEventListener('mouseenter', () => showHideElement(list, true));
menu.addEventListener('mouseleave', () => showHideElement(list, false));
#menu > ul {
  height: 0;
  overflow: hidden;
  background-color: #999;
  transition: height .25s ease-out;
}

#menu > ul.open {
  height: auto;
}
<div id="menu">
  <a>hover me</a>
  <ul>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
  </ul>
</div>

于 2019-02-15T11:51:27.693 回答
5

Jake 对 max-height 进行动画处理的答案很棒,但我发现设置较大的 max-height 造成的延迟很烦人。

可以将可折叠内容移动到内部 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

这是一个jsfiddle,所需的代码绝对最少:http: //jsfiddle.net/8ncjjxh8/

于 2013-08-17T01:46:18.080 回答
5
于 2013-10-09T22:35:11.150 回答
5

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

您可以指定heighton .parent、 in px%或 leave as auto.child然后当它向下滑动时,这个 div 会掩盖掉div。

于 2014-03-13T23:19:41.713 回答
5

我想我想出了一个非常可靠的解决方案

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

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

就是这样!此解决方案使用MutationObserver来跟踪 DOM 中的更改。正因为如此,您实际上不必设置任何东西或使用 javascript 来手动设置动画。自动跟踪更改。但是,因为它使用了 MutationObserver,所以这只会在 IE11+ 中转换。

小提琴!

于 2015-05-19T07:25:01.217 回答
5

您可以通过使用剪辑路径创建反向(折叠)动画来做到这一点。

#child0 {
    display: none;
}
#parent0:hover #child0 {
    display: block;
    animation: height-animation;
    animation-duration: 200ms;
    animation-timing-function: linear;
    animation-fill-mode: backwards;
    animation-iteration-count: 1;
    animation-delay: 200ms;
}
@keyframes height-animation {
    0% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 0%, 0% 0%);
    }
    100% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 100%, 0% 100%);
    }
}
<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>

于 2020-02-23T14:42:20.633 回答
5

line-height使用、paddingopacity的替代纯 CSS 解决方案margin

body {
  background-color: linen;
}

main {
  background-color: white;
}

[id^="toggle_"] ~ .content {
  line-height: 0;
  opacity: 0;
  padding: 0 .5rem;
  transition: .2s ease-out;
}

[id^="toggle_"] ~ .content > p {
  margin: 0;
    transition: .2s ease-out;
}

[id^="toggle_"]:checked ~ .content   {
  opacity: 1;
  padding: .5rem;
  line-height: 1.5;
}

[id^="toggle_"]:checked ~ .content p  {
    margin-bottom: .75rem;
}

[id^="toggle_"] + label {
  display: flex;
  justify-content: space-between;
  padding: 0.5em 1em;
  background: lightsteelblue;
  border-bottom: 1px solid gray;
  cursor: pointer;
}

[id^="toggle_"] + label:before {
  content: "Show";
}

[id^="toggle_"]:checked + label:before {
  content: "Hide";
}

[id^="toggle_"] + label:after {
  content: "\25BC";
}

[id^="toggle_"]:checked + label:after {
  content: "\25B2";
}
<main>
    <div>
        <input type="checkbox" id="toggle_1" hidden>
        <label for="toggle_1" hidden></label>
        <div class="content">
            <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dolor neque, commodo quis leo ut, auctor tincidunt mauris. Nunc fringilla tincidunt metus, non gravida lorem condimentum non. Duis ornare purus nisl, at porta arcu eleifend eget. Integer lorem ante, porta vulputate dui ut, blandit tempor tellus. Proin facilisis bibendum diam, sit amet rutrum est feugiat ut. Mauris rhoncus convallis arcu in condimentum. Donec volutpat dui eu mollis vulputate. Nunc commodo lobortis nunc at ultrices. Suspendisse in lobortis diam. Suspendisse eget vestibulum ex.
            </p>
        </div>
    </div>
    <div>
        <input type="checkbox" id="toggle_2" hidden>
        <label for="toggle_2" hidden></label>
        <div class="content">
            <p>
                Maecenas laoreet nunc sit amet nulla ultrices auctor. Vivamus sed nisi vitae nibh condimentum pulvinar eu vel lorem. Sed pretium viverra eros ut facilisis. In ut fringilla magna. Sed a tempor libero. Donec sapien libero, lacinia sed aliquet ut, imperdiet finibus tellus. Nunc tellus lectus, rhoncus in posuere quis, tempus sit amet enim. Morbi et erat ac velit fringilla dignissim. Donec commodo, est id accumsan cursus, diam dui hendrerit nisi, vel hendrerit purus dolor ut risus. Phasellus mattis egestas ipsum sed ullamcorper. In diam ligula, rhoncus vel enim et, imperdiet porta justo. Curabitur vulputate hendrerit nisl, et ultricies diam. Maecenas ac leo a diam cursus ornare nec eu quam.
            </p>
            <p>Sed non vulputate purus, sed consectetur odio. Sed non nibh fringilla, imperdiet odio nec, efficitur ex. Suspendisse ut dignissim enim. Maecenas felis augue, tempor sit amet sem fringilla, accumsan fringilla nibh. Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus in ante molestie tincidunt. Morbi luctus orci eu egestas dignissim. Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit.
            </p>
            <p>Aenean aliquam risus id consectetur sagittis. Aliquam aliquam nisl eu augue accumsan, vel maximus lorem viverra. Aliquam ipsum dolor, tempor et justo ac, fermentum mattis dui. Etiam at posuere ligula. Vestibulum tortor metus, viverra vitae mi non, laoreet iaculis purus. Praesent vel semper nibh. Curabitur a congue lacus. In et pellentesque lorem. Morbi posuere felis non diam vulputate, non vulputate ex vehicula. Vivamus ultricies, massa id sagittis consequat, sem mauris tincidunt nunc, eu vehicula augue quam ut mauris.
            </p>
        </div>
    </div>
        <div>
        <input type="checkbox" id="toggle_3" hidden>
        <label for="toggle_3" hidden></label>
        <div class="content">
            <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dolor neque, commodo quis leo ut, auctor tincidunt mauris. Nunc fringilla tincidunt metus, non gravida lorem condimentum non. Duis ornare purus nisl, at porta arcu eleifend eget. Integer lorem ante, porta vulputate dui ut, blandit tempor tellus. Proin facilisis bibendum diam, sit amet rutrum est feugiat ut. Mauris rhoncus convallis arcu in condimentum. Donec volutpat dui eu mollis vulputate. Nunc commodo lobortis nunc at ultrices. Suspendisse in lobortis diam. Suspendisse eget vestibulum ex.
            </p>
            <p>Sed non vulputate purus, sed consectetur odio. Sed non nibh fringilla, imperdiet odio nec, efficitur ex. Suspendisse ut dignissim enim. Maecenas felis augue, tempor sit amet sem fringilla, accumsan fringilla nibh. Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus in ante molestie tincidunt. Morbi luctus orci eu egestas dignissim. Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit.
            </p>
        </div>
    </div>
</main>

于 2021-04-28T17:38:15.970 回答
4

我意识到这个帖子已经过时了,但它在某些谷歌搜索中排名很高,所以我认为它值得更新。

您也只需获取/设置元素自身的高度:

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

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

于 2011-05-27T01:13:38.913 回答
4

这是我刚刚与 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 }
于 2011-11-02T23:58:53.190 回答
4

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

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,该 div 最初显示的内容最高为 200px 高度,并且在悬停时它的大小至少与 div 的整个内容一样高。Div 不会变成 3000px,但 3000px 是我强加的限制。确保在非 :hover 上有过渡,否则你可能会得到一些奇怪的渲染。这样 :hover 继承自非 :hover 。

从 px 到 % 或到 auto 的转换不起作用。您需要使用相同的计量单位。

于 2013-03-06T23:13:00.197 回答
3

如果提供的硬编码 max-height 值不比实际高度大很多,那么 Jake 的 max-height 解决方案效果很好(因为否则会出现不希望的延迟和计时问题)。另一方面,如果硬编码值意外地不大于实际高度,则元素将不会完全打开。

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

想法是对 margin-bottom 使用负值(或 margin-top 用于稍微不同的动画)并将内容元素放置在具有溢出:隐藏的中间元素中。内容元素的负边距降低了中间元素的高度。

下面的代码在 margin-bottom 上使用从 -150px 到 0px 的过渡。只要内容元素不高于 150 像素,仅此一项就可以正常工作。此外,它对中间元素的最大高度使用了从 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 的绝对值小于实际高度,则 tansition 会稍微跳跃。在过渡之后的任何情况下,内容元素要么完全显示,要么完全删除。

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

于 2014-08-08T09:24:26.120 回答
3

很多答案,有些比其他更好,大多数使用 JS。我相信我在两个易于理解的用例中发现了这一点,尽管其中一个目前仅适用于 Firefox。

如果您想切换叠加层,这适用于每个浏览器:

.demo01 {
  overflow: hidden;
  position: absolute;
  pointer-events: none;
}
.demo01__content {
  background: lightgray;
  padding: 1rem;
  pointer-events: all;
  transform: translateY(-100%);
  transition: transform 1s, visibility 1s;
  visibility: hidden;
}
:checked ~ .demo01 .demo01__content {
  transform: translateY(0);
  visibility: visible;
}
<input type="checkbox" /> ⬅︎ Toggle
<div>Something before </div>
<div class="demo01">
  <div class="demo01__content">
    This content should…&lt;br />
    toggle! 
  </div>
</div>
<div>Something after </div>

这(目前)仅适用于 Firefox,用于切换文档流:

.demo02 {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows 1s;
}
.demo02__content {
  align-self: end;
  min-height: 0;
  background: lightgray;
  transition: visibility 1s;
  visibility: hidden;
}
.demo02__padding {
  padding: 1rem;
}
:checked ~ .demo02 {
  grid-template-rows: 1fr;
}
:checked ~ .demo02 .demo02__content {
  visibility: visible;
}
<input type="checkbox" /> ⬅︎ Toggle
<div>Something before </div>
<div class="demo02">
  <div class="demo02__content">
    <div class="demo02__padding">
      This content should…&lt;br />
      toggle! 
    </div>
  </div>
</div>
<div>Something after </div>

我写了一篇关于这些技术的博客文章,其中包含需要修复才能 100% 可用的 Chromium 错误的链接。

于 2021-11-01T20:00:45.690 回答
2

这并不完全是问题的“解决方案”,而更像是一种解决方法。它只能与文本一起使用,但可以根据需要更改为与其他元素一起使用,我敢肯定。

.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

本质上,您将 font-size 设置为 0 并以足够快的速度转换它而不是 height、max-height 或 scaleY() 等,以使高度转换为您想要的。目前无法使用 CSS 将实际高度转换为 auto,但是转换其中的内容是,因此字体大小转换。

  • 注意 - codepen 中有 javascript,但它的唯一目的是在点击手风琴时添加/删除 css 类。这可以通过隐藏的单选按钮来完成,但我并没有专注于那个,只是高度变换。
于 2016-10-12T00:12:46.370 回答
2

我结合了最大高度和负边距来实现这个动画。

我使用了 max-height: 2000px,但如果需要,您可以将该数字推到更高的值。我为展开时的最大高度和折叠时的边距设置动画。

js 部分只是点击,可以替换为 :hover 或纯 css 解决方案的复选框。

到目前为止,我只能看到 2 个问题,

  1. 过渡时间是有限的。(我只添加了 2 个时间)
  2. 如果在下拉列表折叠时再次单击,它将跳转。

这是结果

[...document.querySelectorAll('.ab')].forEach(wrapper => {
    wrapper.addEventListener('click', function () {
        this.classList.toggle('active');
    });
});
* {
  margin: 0;
  box-sizing: border-box;
}

.c {
  overflow: hidden;
}

.items {
  width: 100%;
  visibility: hidden;
  max-height: 0;
  margin-bottom: -2000px;
  -webkit-transition: margin 0.6s cubic-bezier(1, 0, 1, 1), max-height 0s 0.6s linear, visibility 0s 0.6s linear;
  transition: margin 0.6s cubic-bezier(1, 0, 1, 1), max-height 0s 0.6s linear, visibility 0s 0.6s linear;
}
.items > * {
  padding: 1rem;
  background-color: #ddd;
  -webkit-transition: background-color 0.6s ease;
  transition: background-color 0.6s ease;
}
.items > *:hover {
  background-color: #eee;
}

.ab {
  padding: 1rem;
  cursor: pointer;
  background: #eee;
}
.ab.active + .c .items {
  max-height: 2000px;
  margin-bottom: 0;
  visibility: visible;
  -webkit-transition: max-height 0.6s cubic-bezier(1, 0, 1, 1);
  transition: max-height 0.6s cubic-bezier(1, 0, 1, 1);
}

.dropdown {
  margin-right: 1rem;
}

.wrapper {
  display: -webkit-box;
  display: flex;
}
<div class="wrapper">
    <div class="dropdown">
        <div class="ab">just text</div>
        <div class="ab">just text</div>
        <div class="ab">dropdown</div>
        <div class="c">
            <div class="items">
                <p>items</p>
                <p>items</p>
                <p>items asl;dk l;kasl;d sa;lk</p>
                <p>items sal;kd</p>
                <p>items</p>
            </div>
        </div>
        <div class="ab">just text</div>
        <div class="ab">just text</div>
    </div>
    
    <div class="dropdown">
        <div class="ab">dropdown</div>
        <div class="c">
            <div class="items">
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
                <p>items</p>
            </div>
        </div>
        <div class="ab">text</div>
    </div>
    
    <div class="dropdown">
        <div class="ab">placeholder</div>
        <div class="ab">dropdown</div>
        <div class="c">
            <div class="items">
                <p>items</p>
                <p>items</p>
            </div>
        </div>
        <div class="ab">placeholder</div>
        <div class="ab">placeholder</div>
        <div class="ab">placeholder</div>
    </div>
</div>
<h1>text to be pushed</h1>

于 2020-09-07T20:54:01.057 回答
2

灵活的高度 CSS Only 解决方案

我偶然发现了一个使用 flex 行为的古怪解决方案。它至少适用于 Chrome 和 Firefox。

  • 首先,高度过渡只在 0 到 100% 之间起作用,这两个数值。由于“auto”不是数值,因此在 0 和“auto”之间不存在小数增量。100% 是一个灵活的值,因此不需要特定的高度。

  • 其次,隐藏内容的外层容器和内层容器都必须设置为 display: flex 和 flex-direction: column。

  • 第三,外部容器必须具有高度属性。高度无关紧要,因为 flex 行为优先于高度,所以我使用高度 0。

.outer-container { height: 0; display: flex; flex-direction: column; }

.inner-container { display: flex; flex-direction: column; }

.hidden-content { 
    height: 0; 
    opacity: 0; 
    transition: height 1s 0.5s ease-in-out, opacity 0.5s ease-in-out;
    /* transition out: first fade out opacity, then shrink height after a delay equal to the opacity duration */
    }

.trigger:hover + .inner-container > .hidden-content { 
    height: 100%; 
    opacity: 1; 
    transition: height 1s ease-in-out, opacity 0.5s 1s ease-in-out;
    /* transition in: first expand height, then fade in opacity after a delay equal to the height duration */
}
<div class="outer-container">
  <a href="#" class="trigger">Hover to Reveal Inner Container's Hidden Content</a>
  <div class="inner-container">
    <div class="hidden-content">This is hidden content. When triggered by hover, its height transitions from 0 to 100%, which pushes other content in the same container down gradually.</div>
    <div>Within the same container, this other content is pushed down gradually as the hidden content's height transitions from 0 to 100%.</div>
  </div>
</div>

按 Run Code Snippet按钮以查看转换的实际效果。它只是 CSS,没有特定的高度。

于 2022-01-08T01:48:57.877 回答
1

似乎没有合适的解决方案。max-height方法非常好,但在隐藏阶段效果不佳 - 除非您知道内容的高度,否则会有明显的延迟。

我认为最好的方法是使用max-height仅用于显示阶段。并且不要在隐藏时使用任何动画。在大多数情况下,它不应该是至关重要的。

max-height应该设置为一个相当大的值,以确保任何内容都适合。可以使用transition持续时间 ( speed = max-height / duration) 控制动画速度。速度不取决于内容的大小。显示整个内容所需的时间将取决于其大小。

document.querySelector("button").addEventListener(
  "click", 
  function(){
    document.querySelector("div").classList.toggle("hide");
  }
)
div {    
    max-height: 20000px;
    transition: max-height 3000ms;
    overflow-y: hidden;
}

.hide {
    max-height: 0;
    transition: none;
}
<button>Toggle</button>
<div class="hide">Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. 
</div>

于 2017-03-24T19:38:47.583 回答
1

我只是动画<li>元素而不是整个容器:

<style>
.menu {
    border: solid;
}
.menu ul li {
    height: 0px;
    transition: height 0.3s;
    overflow: hidden;
}
button:hover ~ .wrapper .menu ul li,
button:focus ~ .wrapper .menu ul li,
.menu:hover ul li {
    height: 20px;
}
</style>


<button>Button</button>
<div class="wrapper">
    <div class="menu">
        <ul>
            <li>menuitem</li>
            <li>menuitem</li>
            <li>menuitem</li>
            <li>menuitem</li>
            <li>menuitem</li>
            <li>menuitem</li>
        </ul>
    </div>
</div>

您可以添加ul: margin 0; 到 0 高度。

于 2020-04-01T16:52:48.977 回答
0

我使用的方法是让所有内容都基于字体大小(使用 em 作为单位)或至少影响我们想要动画打开的框的垂直大小的所有内容。然后,如果任何东西不在 em 单位中(例如 1px 边框),我会在盒子关闭时将其设置为 0,通过使用 *.

动画的动画是从 0 到 100 的字体大小(以 % 为单位)。其中是什么?父级的已知字体大小。

它的工作规则是动画框中的所有内容都必须:

  • 对所有字体大小和行高使用 %
  • 将 em 用于垂直的所有内容(如高度、边距和填充顶部/底部等)
  • 如果将 px 用于垂直的东西(例如边框顶部/底部),它应该在盒子关闭时被覆盖(例如border-top:0;border-bottom:0;

在某种程度上,您仍然可以使用像素作为参考单位,只需将包装器字体大小设置为 100px,例如#page{font-size:100px;},如果您想要 10px 在内部任何地方都可以使用0.1em.

这不是任何人都能写出的最漂亮的东西,但是,嘿,这些浏览器并没有为我们提供任何漂亮的解决这个问题的方法。一旦盒子的高度无法预测,我们别无选择,只能弄脏一些,这是我想出的最不脏的东西。

悬停版本:

https://jsfiddle.net/xpsfkb07/1/

#page {
  font-size: calc( (35vw + 65vh) / 30); /* just some responsive design as a bonus */
}
#slidebox {
  background-color: #e8e8e8;
  visibility: hidden;
  font-size: 0; /* animated from 0 to 100% */
  opacity: 0; /* optional */
  transition: 0.5s;
}
a#ahover:hover ~ #slidebox {
  visibility: visible;
  font-size: 100%; /* animated from 0 to 100% */
  opacity: 1; /* optional */
}
a#ahover:not(:hover) ~ #slidebox * {
  border-top: 0;
  border-bottom: 0;
  /* Put here anything vertical that uses px as unit, in this case the borders */
}
a#button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 20em;
  height: 3em;
  padding: 0.5em;
  border: 2px solid #0080ff;
  border-radius: 0.4em;
  background-color: #8fbfef;
  color: #404040;
  box-sizing: border-box;
}
#someform {
  margin-top: 1em;
  margin-bottom: 1em;
  padding: 1em 4em 1em 4em;
  background-color: #d8ffd8;
  border: 1px solid #888888;
}
#someform input {
  display: inline-block;
  box-sizing: border-box;
  font-size: 125%;
  padding: 0.5em;
  width: 50%; /* anything horizontal can still be in px or % */
  border-radius: 0.4em;
  border: 1px solid red;
}
<div id=page>
  <a id=ahover href="#">Hover me</a><br>
  Here is the box that slides:
  <div id=slidebox>
    I am the content of the slide box (line1).<br>
    I am the content of the slide box (line2).<br>
    <a id=button href="#">I am some button in the slide box</a><br>
    I am the content of the slide box (line3).<br>
    I am the content of the slide box (line4).
    <div id=someform>
      Some box with a form or anything...<br>
      <input type=text value="Text Box">
    </div>
    I am the content of the slide box (line5).<br>
    I am the content of the slide box (line6).
  </div>
  And this is after the box.
</div>

类更改版本:

https://jsfiddle.net/8xzsrfh6/

const switch_ele = document.getElementById('aclass');
switch_ele.addEventListener('click', function(){
    const box_ele = document.getElementById('slidebox');
    box_ele.className = box_ele.className == 'show' ? 'hide' : 'show';
}, true);
#page {
  font-size: calc( (35vw + 65vh) / 30); /* just some responsive design as a bonus */
}
#slidebox {
  background-color: #e8e8e8;
  visibility: hidden;
  font-size: 0; /* animated from 0 to 100% */
  opacity: 0; /* optional */
  transition: .5s;
}
#slidebox.show {
  visibility: visible;
  font-size: 100%; /* animated from 0 to 100% */
  opacity: 1; /* optional */
}
#slidebox.hide * {
  border-top: 0;
  border-bottom: 0;
  /* Put here anything vertical that uses px as unit, in this case the borders */
}
a#button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 20em;
  height: 3em;
  padding: 0.5em;
  border: 2px solid #0080ff;
  border-radius: 0.4em;
  background-color: #8fbfef;
  color: #404040;
  box-sizing: border-box;
}
#someform {
  margin-top: 1em;
  margin-bottom: 1em;
  padding: 1em 4em 1em 4em;
  background-color: #d8ffd8;
  border: 1px solid #888888;
}
#someform input {
  display: inline-block;
  box-sizing: border-box;
  font-size: 125%;
  padding: 0.5em;
  width: 50%; /* anything horizontal can still be in px or % */
  border-radius: 0.4em;
  border: 1px solid red;
}
<div id=page>
  <a id=aclass href="#">Switch class w/ js</a><br>
  Here is the box that slides:
  <div id=slidebox class=hide>
    I am the content of the slide box (line1).<br>
    I am the content of the slide box (line2).<br>
    <a id=button href="#">I am some button in the slide box</a><br>
    I am the content of the slide box (line3).<br>
    I am the content of the slide box (line4).
    <div id=someform>
      Some box with a form or anything...<br>
      <input type=text value="Text Box">
    </div>
    I am the content of the slide box (line5).<br>
    I am the content of the slide box (line6).
  </div>
  And this is after the box.
</div>

于 2021-10-08T06:23:55.740 回答
0

我想添加一个关于如何扩展/折叠保持文档流的示例,此示例适用于使用 tailwindcss 的 React 应用程序

export function Collapse({ collapsed = true, children }) {
  return (
    <div className="grid">
      <div className="flex flex-col">
        <div className={`transition-all duration-500 overflow-hidden ${collapsed ? 'basis-0' : 'flex-1'}`}>
          {children}
        </div>
      </div>
    </div>
  );
}

深入阅读:https ://stackoverflow.com/a/69871346/9226510

于 2022-01-06T02:17:13.903 回答
-1

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

在 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%; /**/
}
于 2012-03-17T04:40:02.313 回答
-1

我通过将最大高度设置为无,获取高度,将最大高度重新设置为计算出的高度来完成这项工作。非常适合我。我把它用于手风琴菜单,用's 作为切换<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;
    }
}
于 2013-09-11T07:19:27.137 回答
-1

小 JAVASCRIPT + SCSS 解决方案

我通常使用完全不同的观点和(非常)小的javascript。事情是:

  • 我们真正想要的是改变高度

  • 高度是子菜单内所有列表项的总和

  • 我们通常知道列表项的高度,因为我们正在对其进行样式设置

所以我的解决方案适用于项目名称只有 1 行的“普通”子菜单。无论如何,多一点 js 可以容纳超过 1 行名称。

基本上,我所做的只是简单地计算子菜单项并相应地应用特定的类。然后将球传给(s)css。因此,例如:

var main_menu = $('.main-menu');
var submenus = $('.main-menu').find('.submenu');
submenus.each(function(index,item){
   var i = $(item);
   i.addClass('has-' + i.find('li').length + '-children');
});

显然,您可以使用任何类/选择器。在这一点上,我们有这样的子菜单:

<ul class="submenu has-3-children">
   <li></li>
   <li></li>
   <li></li>
</ul>

我们的css是这样的:

.submenu{
   //your styles [...]
   height:0;
   overflow:hidden;
   transition: all 200ms ease-in-out; //assume Autoprefixer is used
}

我们还将有一些像这样的 scss 变量(任意示例):

$sub_item_height:30px;
$sub_item_border:2px;

在这一点上,假设打开的主菜单项将获得类似“opened”之类的类(你的实现..),我们可以这样做:

//use a number of children reasonably high so it won't be overcomed by real buttons
.main-menu .opened .submenu{
   &.has-1-children{ height:   $sub_item_height*1  + $sub_item_border*1;  }
   &.has-2-children{ height:   $sub_item_height*2  + $sub_item_border*2;  }
   &.has-3-children{ height:   $sub_item_height*3  + $sub_item_border*3;  }
   //and so on....
}

或者,缩短:

.main-menu .opened .submenu{
   @for $i from 1 through 12{//12 is totally arbitrary
      &.has-#{$i}-children { height: $menu_item_height * $i + $menu_item_border * $i; }
   }
}

在大多数情况下,这将完成这项工作。希望能帮助到你!

于 2016-01-25T10:47:33.630 回答
-1

我不愿发布此内容,因为它违反了问题的“无 javascript”部分;但无论如何都会这样做,因为它会在 yScale 答案https://stackoverflow.com/a/17260048/6691上扩展,因此可以将其视为解决该答案的“实际上并没有删除空间”问题,与当 JavaScript 被禁用时,基本的缩放效果仍然有效。

另一个警告是,这不应与一般的“悬停”CSS 规则一起使用,而应仅在通过在 JavaScript 中添加类触发转换时使用,此时您将触发限时执行requestAnimationFrame逻辑。下面的 jsfiddle 示例出于演示目的在后台连续运行,这不适合有其他事情发生的普通网站。

这是演示:http: //jsfiddle.net/EoghanM/oa5dprwL/5/

基本上,我们使用在应用转换requestAnimationFrame后监控框的结果高度scaleYel.getBoundingClientRect().heightget this),然后margin-bottom在元素上应用负数以“吃掉”空白空间。

这适用于任何转换效果;我还添加了一个带有透视的旋转演示。

我没有包含维护元素上任何现有边距底部的代码。

于 2019-11-07T10:55:05.213 回答
-1

.menu {
    margin: 0 auto;
    padding: 0;
    list-style: none;
    text-align: center;
    max-width: 300px;
    width: 100%;
}

.menu li {
    display: block;
    margin-bottom: 5px;
}
.menu li a {
    color: #333;
    display: inline-block;
    font-size: 20px;
    line-height: 28px;
    font-weight: 500;
    font-family: "Poppins", sans-serif;
    transition: all 0.5s;
    margin: 0 0 10px;
}

.menu li.submenu .submenu_item {
    margin: 0;
    padding: 0;
    width: 100%;
    max-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: row;
    text-align: center;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    transition: max-height 1s ease-out !important;
    transition-delay: 0s !important;
}

.menu li.submenu:hover .submenu_item {
    max-height: 1000px;
    transition: max-height 2s ease-in !important;
}

.menu li.submenu .submenu_item li {
    margin-bottom: 0;
    width: 100%;
    display: block;
    margin: 0;
    padding: 0;
    list-style: none;
    position: relative;
}
<p>First you should complete markup  like this</p>

<ul class="menu">
  <li class="submenu">
    <a href="#">Home</a>
    <ul class="submenu_item">
        <li><a href="index.html">Default</a></li>
        <li><a href="index-2.html">Particle</a></li>
        <li><a href="index-3.html">Youtube Video</a></li>
        <li><a href="index-4.html">Self Hosted Video</a></li>
        <li><a href="index-5.html">Slideshow</a></li>
    </ul>
  </li>
</ul>

于 2020-02-11T07:21:43.437 回答
-1

正确的解决方案

滚动高度

你应该使用document.getElementById(id).style.maxHeight = document.getElementById(id).scrollHeight+"px".

在 CSS 中:transition: max-height 1s ease-in-out;

于 2020-04-03T03:02:01.553 回答
-1

如果您希望组从上到下打开(如JHipster网页)而不影响字体或进行任何奇怪的转换并且正在使用预处理器,您可以使用以下


  $item-height: 45px;
  $item-transition: 0.1s;

  ul li:not(.opened) > ul li {
    height: 0;
    @for $i from 1 through 15 {
      &:nth-last-child(#{$i}){
        transition: height $item-transition ease-out #{($i - 1) * $item-transition};
      }
    }
  }
  ul li.opened > ul li {
    height: $item-height;
    @for $i from 1 through 15 {
      &:nth-child(#{$i}){
        transition: height $item-transition ease-out #{($i - 1) * $item-transition};
      }
    }
  }
于 2021-08-31T23:49:33.323 回答
-1

采用max-height

(其他答案的变化)

其中许多答案都在谈论使用(或不使用)max-height。这是可行的,但动画经常会出现延迟或其他不愉快的问题。

这可以通过使用以下方法来实现:

HTML:

<ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
</ul>

CSS:

ul {
    max-height: 0;
    overflow-y: hidden;
    transition: 0.2s;
}
ul:hover {
    max-height: 100%;
    overflow-y: auto;
}

这会将元素缩放到它的全auto高,同时允许过渡和动画没有奇怪的延迟。

兼容性: 除了 Chrome 98、IE11 和 Edge 之外,我还没有测试过这个;它完美地适用于所有这些浏览器。

显然,这也仅适用于支持的浏览器max-heightcaniuse.com

编辑:添加overflow-y: auto;ul:hover因为某些元素可能会出现一些问题。

于 2022-02-22T15:12:03.300 回答
-2

这是我已经解决的常规问题

http://jsfiddle.net/ipeshev/d1dfr0jz/

尝试将关闭状态的延迟设置为某个负数并稍微使用该值。你会看到不同之处。它几乎可以被人眼欺骗;)。

它适用于主要浏览器,但对我来说已经足够了。这很奇怪,但给出了一些结果。

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

button:hover ~ .expandable {
    max-height: 9000px;
    transition: all 1s ease-in-out;
}
于 2015-07-21T11:19:37.650 回答
-2

查看关于一个相关问题的帖子。

基本上,从 开始height: 0px;,让它过渡到 JavaScript 计算的精确高度。

function setInfoHeight() {
  $(window).on('load resize', function() {
    $('.info').each(function () {
      var current = $(this);
      var closed = $(this).height() == 0;
      current.show().height('auto').attr('h', current.height() );
      current.height(closed ? '0' : current.height());
    });
  });

每当页面加载/调整大小时,具有类的元素info都会h更新其属性。然后一个按钮触发将style="height: __"其设置为先前设置的h值。

function moreInformation() {
  $('.icon-container').click(function() {
    var info = $(this).closest('.dish-header').next('.info'); // Just the one info
    var icon = $(this).children('.info-btn'); // Select the logo

    // Stop any ongoing animation loops. Without this, you could click button 10
    // times real fast, and watch an animation of the info showing and closing
    // for a few seconds after
    icon.stop();
    info.stop();

    // Flip icon and hide/show info
    icon.toggleClass('flip');

    // Metnod 1, animation handled by JS
    // info.slideToggle('slow');

    // Method 2, animation handled by CSS, use with setInfoheight function
    info.toggleClass('active').height(icon.is('.flip') ? info.attr('h') : '0');

  });
};

这是info该类的样式。

.info {
  padding: 0 1em;
  line-height: 1.5em;
  display: inline-block;
  overflow: hidden;
  height: 0px;
  transition: height 0.6s, padding 0.6s;
  &.active {
    border-bottom: $thin-line;
    padding: 1em;
  }
}

样式可能不支持跨浏览器。这是此代码的实时示例:

代码笔

于 2016-07-01T19:12:46.810 回答
-3

我今天一直在研究这个问题,并遇到了这个解决方案:

使用 max-height 并根据容器内容的计算高度动态设置 max-height

$(obj).children().each(function(index, element) {
   InnerHeight += $(this).height();
});

动画到全尺寸:

$(obj).removeClass('collapsed').css('max-height', InnerHeight);

动画到更小的尺寸:

$(obj).removeClass('collapsed').css('max-height', MySmallerHeight);

使用 CSS3 过渡:最大高度;

通过这种方式,您可以避免从高到高的看起来有问题的动画,并且您不会冒剪裁内容的风险。

于 2014-02-20T19:51:16.997 回答
-3

我遇到了这个问题并找到了解决方法。

首先我尝试使用max-height. 但是有两个问题:

  1. 我不太确定 是什么max-height,因为我正在扩展一个未知长度的文本块。
  2. 如果我设置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);
}
于 2014-03-03T03:04:09.697 回答
-3

短代码示例:

.slider ul {
  overflow: hidden;
  -webkit-transition: max-height 3.3s ease;
}

.slider.hide ul {
  max-height: 0px;
}

.slider.show ul {
  max-height: 1000px;
}
于 2014-03-12T13:02:40.297 回答
-3

怎么样,而不是高度,你使用类似下面的东西

#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. 同时,您可以单独或全部添加高度过渡。

于 2016-09-02T08:42:34.560 回答
-3

这对我有用:

  .hide{
    max-height: 0px;
    overflow: hidden;
    transition:max-height .5s ease-in-out;
  }

  .show{
    max-height: 150px; // adjust as needed
    transition: max-height .5s ease-in-out;
  }

您需要将它们放在所有子组件中并使用 jQuery 或 React 状态切换它们,这是我的情况(使用 next.js 和 styled-components):https ://codesandbox.io/s/ol3kl56q9q

于 2019-02-09T08:34:37.780 回答
-3

我想让一个 div 滑动打开/关闭,不仅垂直,而且水平,​​所以它有效地从左上角滑到右下角。在研究时,我遇到了这个问题,但答案主要是变通方法和近似值。我想要一种更精确的方法……最后我找到了一种方法。

基本上我下面的代码实现了这一点:

  1. 平滑的过渡在您想要的位置开始和结束,因此缓入/缓出是真正的缓入/缓出
  2. 没有关于高度或宽度或最大高度和宽度的假设。没有硬编码的数字
  3. 在调整包含 div 的大小后,转换也有效(通过窗口调整大小或以编程方式)
  4. 当宽度变得太小时,内容 div 会垂直自动滚动(但在过渡期间不会这样做
  5. HTML 代码或 CSS 中不需要特定的结构。只有一个类中的过渡定义(.anim)

所以这里是:

<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>
于 2019-11-14T21:22:56.827 回答
-4

如果你使用 React,我可以推荐react-animate-height

<AnimateHeight height={isOpen ? 'auto' : 0}>
  // your content goes here
</AnimateHeight>
于 2020-02-26T14:40:35.900 回答
-5

来源

这太晚了,但为了未来的研究人员,我会发布我的答案。我相信你们中的大多数人都在寻找 height : 0 是为了 td 或 tr 切换过渡动画或类似的东西。但是在 td 或 tr 上仅使用 height、max-height、line-height 是不可能的,但是您可以使用以下技巧来实现它:

  • 将所有 td 内容包装到 div 中并使用 height: 0 + overflow: hidden + white-space: nowrap on divs ,以及您选择的动画/过渡
  • 使用变换:scaleY (͡° ͜ʖ ͡°)
于 2021-02-09T02:35:36.020 回答
-6

这是我一直在使用的。

基本上,我得到所有子元素的高度,总结它们,然后设置元素的最大高度,覆盖类(你可以让你自己的类,所以你可以有不同的实例)。

看看这个。

                            <!doctype html>
                            <html>

                            <head>
                                <style>
                                    /* OVERFLOW HIDDEN */
                                    .overflowHidden{
                                        overflow: hidden;
                                    }

                                    /* HEIGHT */
                                    .transitionHeight{
                                        -webkit-transition: max-height 250ms ease-in-out;
                                        -moz-transition: max-height 250ms ease-in-out;
                                        -o-transition: max-height 250ms ease-in-out;
                                        -ms-transition: max-height 250ms ease-in-out;
                                        transition: max-height 250ms ease-in-out;
                                    }
                                    .heightAnimOff{
                                        height: auto;
                                        max-height: 0px;
                                    }
                                    .heightAnimOn{
                                        height: auto;
                                        max-height: 20000px;
                                    }

                                </style>
                                <script src="jquery_1.8.3.min.js" type="text/javascript"></script>
                                <script type="text/javascript">
                                    (function($){
                                            $.toggleAnimHeight = function(alvo, velha, nova){
                                                if ( $(alvo).attr("data-maxHeight") != null ){
                                                }else{
                                                    var totalH = 0;
                                                    $(alvo).children().each(function(){
                                                        totalH += $(this).height();
                                                    });
                                                    $(alvo).attr("data-maxHeight", totalH)
                                                    $("head").append('<style> .'+nova+'{ max-height: '+totalH+'px; } </style>');
                                                }           
                                                if ( $(alvo).attr("class").indexOf(nova) == -1 ){
                                                    $(alvo).removeClass(velha);
                                                    $(alvo).addClass(nova);
                                                }else {
                                                    $(alvo).removeClass(nova);
                                                    $(alvo).addClass(velha);
                                                }
                                            }
                                    }(jQuery));
                                </script>
                            </head>

                            <body>
                                <div class="animContainer">
                                    <button onmousedown="$.toggleAnimHeight( $('#target1'), 'heightAnimOff', 'heightAnimOn' );">Anim Toggle</button>
                                    <div id="target1" class="overflowHidden heightAnimOff transitionHeight">
                                        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id pretium enim, quis faucibus urna. Phasellus blandit nisl eget quam mollis vulputate. Sed pulvinar eros vitae neque volutpat, vitae suscipit urna viverra. Etiam rhoncus purus vitae tortor pulvinar, sed vulputate arcu convallis. Sed porta, mi consectetur convallis semper, odio mauris iaculis purus, non tempor purus augue pharetra lorem. Integer dictum lacus arcu. Vivamus metus lorem, fermentum ac egestas ac, ornare non neque. Aenean ullamcorper adipiscing ante, et mollis orci feugiat et.</p>

                                        <p>Praesent pretium sit amet eros et lacinia. Etiam nec neque ullamcorper, sagittis quam vitae, dictum ipsum. Sed volutpat lorem libero, nec commodo magna posuere rutrum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque id erat odio. Sed faucibus sem eu tortor laoreet pulvinar. Praesent pharetra risus eget metus vulputate, eget condimentum leo consequat. Praesent consequat rutrum convallis.</p>

                                        <p>Aenean euismod metus quis libero commodo, tristique cursus odio vestibulum. Donec quis lobortis arcu, eu luctus diam. In eget nisi non mauris commodo elementum. Sed gravida leo consequat, tempus orci eu, facilisis ipsum. Cras interdum sed odio vel tincidunt. Morbi arcu ipsum, ultricies dictum enim quis, varius dignissim massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec semper, magna eu aliquam luctus, leo purus accumsan massa, at auctor dui dolor eu augue. Maecenas ultrices faucibus ante non mattis.</p>

                                        <p>Pellentesque ut est tortor. Quisque adipiscing ac nisi vel interdum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut facilisis ante sollicitudin vehicula ornare. Quisque sagittis diam nibh, ac imperdiet nibh pulvinar eu. Integer at ipsum a purus tristique porttitor vitae in ante. Sed arcu neque, lacinia eu dolor nec, pellentesque interdum tortor. Morbi ornare aliquet aliquam. Aenean egestas, erat vel tempus mollis, est eros iaculis enim, quis fringilla purus tortor sollicitudin erat. Donec ultrices elit metus, sed iaculis mi dignissim vulputate. Donec adipiscing imperdiet porttitor. Sed ac lacus adipiscing, sagittis sem quis, tincidunt metus. Curabitur vitae augue a dolor scelerisque lobortis ut a nisi.</p>

                                        <p>Quisque sollicitudin diam sit amet dui sollicitudin, ac egestas turpis imperdiet. Nullam id dui at lectus ultrices aliquam. Nam non luctus tortor, vitae elementum elit. Nullam id bibendum orci. Aliquam hendrerit nisi vitae tortor mollis, nec aliquam risus malesuada. In scelerisque nisl arcu, sit amet tincidunt libero consequat pharetra. Quisque aliquam consectetur purus nec sollicitudin. Pellentesque consectetur eleifend tortor in blandit. Pellentesque euismod justo sed lectus congue, ut malesuada diam rhoncus. Nulla id tempor odio. Nulla facilisi. Phasellus lacinia neque in nisi congue aliquet. Aliquam malesuada accumsan mauris eget mattis. Maecenas pellentesque, sem sed ultricies ullamcorper, massa enim consectetur magna, eget sagittis lorem leo vel arcu. Cras ultrices nunc id risus commodo laoreet. Proin nisl nulla, elementum ac libero sed, aliquam mollis massa.</p>
                                    </div>
                                </div>
                            </body>

                            </html>
于 2013-10-03T16:47:25.690 回答