如何转换高度:0;达到高度:自动;使用CSS?

2010-08-18 css css-transitions

我正在尝试使用CSS过渡使<ul>滑落。

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

Answers

您可以用一点点非语义性的扑克游戏。我通常的方法是为外部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>

我的解释是动画运行需要明确的高度。当height(开始高度或结束高度)均为auto时,无法获得高度动画。

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

您可以从height:0转换为height:auto,前提是您还提供了min-height和max-height。

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

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

我意识到该线程已经过时,但是在某些Google搜索中它的排名很高,因此我认为值得进行更新。

您还可以获取/设置元素自己的高度:

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

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

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

您还不能完全获得擦除效果,但是使用过渡时间和填充值应该可以使您足够接近。如果您不想显式设置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/ (从stephband的jsFiddle上方摘下来)

这是我刚与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);
    });

然后,您可以使用click函数通过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 }

在过渡中使用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>

将高度设置为自动,然后过渡最大高度。

在Chrome v17上测试

div {
  position: absolute;
  width:100%;
  bottom:0px;
  left:0px;

  background:#333;
  color: #FFF;

  max-height:100%; /**/
  height:auto; /**/

  -webkit-transition: all 0.2s ease-in-out;
  -moz-transition: all 0.2s ease-in-out;
  -o-transition: all 0.2s ease-in-out;
  -ms-transition: all 0.2s ease-in-out;
  transition: all 0.2s ease-in-out;
}

.close {
  max-height:0%; /**/
}

我的解决方法是将max-height转换为精确平滑的内容高度,然后使用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>

我也使用jQuery完成此操作。就我而言,我想看一下其他菜单(10像素)。因此,这无需Javascript就可以使用(但也没有过渡)。

#menu li ul {
        list-style: none;
        height: 10px;
        overflow: hidden;
        margin: 0;
        padding: 0;
    }
        #menu li:hover ul {
            height: 100%;
        }

这是我的js:

//Save the height set in css (10px)
var csshoehe = $("ul li ul").height();

// Open all the menus
$("ul li ul").css("height", "100%");

//Save each height in data-attribute
//then shrink it down again
$.each($("ul li ul"), function(){
    var hoehe = $(this).height();
    $(this).data("hoehe", hoehe);
    $(this).css("height", csshoehe);
});

$("ul li").hover(
    function(){
        var orig = $(this).children("ul").data("hoehe");
        $(this).children("ul").stop(true,false).delay(150).animate({"height": orig});
},  function(){
        $(this).children("ul").stop(true,false).delay(400).animate({"height": csshoehe});
});

希望这可以帮助某人:)

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

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首先显示最高200像素的高度,然后将其悬停,其大小至少应与div的整个内容一样高。 Div不会变为3000px,但我要施加的极限是3000px。确保在non:hover上进行过渡,否则可能会得到一些奇怪的渲染。这样,:hover将从非:hover继承。

从px到%或自动的过渡均无效。您需要使用相同的度量单位。 这对我来说很好。使用HTML5使其完美。

请记住,总有解决方法……; )

希望有人觉得这有用

您应该改用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,而不是高度。

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

杰克(Jake)设置最大高度动画的答案很棒,但我发现设置较大的最大高度烦人会造成延迟。

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

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

这是一个jsfiddle链接: http : //jsfiddle.net/pbatey/duZpT

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

通过将max-height设置为none,获取高度,然后将max-height重置为计算的高度,可以使此工作正常进行。非常适合我。我得到这个工作的手风琴菜单,用<h5>的作为toggler扩大<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;
    }
}

这就是我一直在使用的。

基本上,我得到所有子元素的高度,对其求和,然后为该元素设置max-height,以覆盖类(您可以使自己的类成为自己,因此可以有不同的实例)。

看看这个。

                            <!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>

编辑:向下滚动以获取更新的答案
我正在制作一个下拉列表,并看到了此帖子……许多不同的答案,但我决定也分享我的下拉列表,……虽然不完美,但至少它将仅使用CSS进行下拉!我一直在使用transform:translateY(y)将列表转换为视图...
您可以在测试中看到更多
http://jsfiddle.net/BVEpc/4/
我将div放在每个li的后面,因为我的下拉列表来自上层,为了正确显示它们是必需的,我的div代码是:

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

悬停是:

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

并且因为ul height设置为内容,所以它可以覆盖您的身体内容,这就是我为ul执行此操作的原因:

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

并悬停:

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

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

编辑:我简直不敢相信ppl实际上使用了这个原型!该下拉菜单仅适用于一个子菜单,仅此而已! 我更新了一个更好的版本,可以在支持IE 8的同时为ltr和rtl方向提供两个子菜单。
LTR小提琴
RTL小提琴
希望将来有人会有用。

这是一种从任何起始高度(包括0)过渡到自动(完整大小和灵活)的方式,而无需在每个节点上进行硬设置代码或初始化任何用户代码: https : //github.com/csuwildcat / transition-auto 。我相信这基本上是您想要的圣杯-> http://codepen.io/csuwldcat/pen/kwsdF 。只需将以下JS文件拍到您的页面中,然后要做的就是从要扩展和收缩的节点中添加/删除一个布尔值属性-“ reveal=""

包含示例代码下面的代码块后,您需要执行的所有操作:

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

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

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

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

这是要包含在您的页面中的代码块,此后,全部都是肉汁:

将此JS文件拖放到您的页面中-Just Works™全部

/ *高度代码:自动;过渡* /

(function(doc){

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

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

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

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

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

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

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

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

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

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

})(document);

/ *演示代码* /

    document.addEventListener('click', function(e){
      if (e.target.nodeName == 'BUTTON') {
        var next = e.target.nextElementSibling;
        next.hasAttribute('reveal') ? next.removeAttribute('reveal') : next.setAttribute('reveal', '');
      }
    }, false);

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

使用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 transition:max-height;

这样一来,您就可以避免出现动画故障的动画,并且不会冒截断内容的风险。

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

首先,我尝试使用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);
}

简短的代码示例:

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

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

.slider.show ul {
  max-height: 1000px;
}

我能够做到这一点。我有一个.child.parent div。孩子的div完全符合母公司的宽度/高度与内absolute定位。然后,我为translate属性设置动画,以将其Y值降低100% 。它的动画非常流畅,没有毛刺或毛刺,没有其他解决方案。

像这样的伪代码

.parent{ position:relative; overflow:hidden; } 
/** shown state */
.child {
  position:absolute;top:0;:left:0;right:0;bottom:0;
  height: 100%;
  transition: transform @overlay-animation-duration ease-in-out;
  .translate(0, 0);
}

/** Animate to hidden by sliding down: */
.child.slidedown {
  .translate(0, 100%); /** Translate the element "out" the bottom of it's .scene container "mask" so its hidden */
}

您可以在.parent上指定height ,以px%或保留为auto 。然后,当该div向下滑动时,该div会掩盖.child div。

我最近一直在将li元素的max-height而不是包装ul过渡。

原因是,与较大的max-heights相比,较小的max-heights的延迟远没有那么明显(如果有的话),我还可以相对于lifont-size设置max-height值,而不是任意设置通过使用emsrems

如果我的字体大小是1rem ,则将max-height设置为3rem (以容纳3rem文本)。您可以在此处查看示例:

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

如果采用硬编码,Jake的最大高度解决方案效果很好 提供的最大高度值不大于实际高度 (因为否则会有不希望的延迟和定时问题)。 另一方面,如果硬编码值偶然是 不大于元素的实际高度不会完全打开。

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

想法是在底边使用负值(或在顶边使用负值) 略有差异的动画),然后将内容元素放入 中间元素带有溢出:隐藏。内容的负边距 因此减少了中间元素的高度。

以下代码在margin-bottom上从-150px过渡到 0px。只要content元素不是 高于150像素。此外,它为 中间元素从0px到100%。最终隐藏了中间元素 如果content元素高于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>

保证金底部的值应为负且与 可能达到内容元素的实际高度。如果是(绝对) 值)较大,存在类似的延迟和计时问题 最大高度的解决方案,但是只要 硬编码的大小并不比实际的大。如果绝对 底边的值小于实际高度 弹跳跳了一点。无论如何,过渡后 内容元素完全显示或完全删除。

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

可接受的答案在大多数情况下都有效,但是当div高度变化很大时,效果并不理想-动画速度不依赖于内容的实际高度,并且看起来不稳定。

您仍然可以使用CSS来执行实际的动画,但是您需要使用JavaScript来计算项目的高度,而不是尝试使用auto 。不需要jQuery,但是如果要兼容,则可能需要稍作修改(在最新版本的Chrome中可用:)。

window.toggleExpand = function(element) {
    if (!element.style.height || element.style.height == '0px') { 
        element.style.height = Array.prototype.reduce.call(element.childNodes, function(p, c) {return p + (c.offsetHeight || 0);}, 0) + 'px';
    } else {
        element.style.height = '0px';
    }
}
#menu #list {
    height: 0px;
    transition: height 0.3s ease;
    background: #d5d5d5;
    overflow: hidden;
}
<div id="menu">
    <input value="Toggle list" type="button" onclick="toggleExpand(document.getElementById('list'));">
    <ul id="list">
        <!-- Works well with dynamically-sized content. -->
        <li>item</li>
        <li><div style="height: 100px; width: 100px; background: red;"></div></li>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
</div>

对每个状态使用max-height不同的过渡缓和和延迟。

HTML:

<a href="#" id="trigger">Hover</a>
<ul id="toggled">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
<ul>

CSS:

#toggled{
    max-height: 0px;
    transition: max-height .8s cubic-bezier(0, 1, 0, 1) -.1s;
}

#trigger:hover + #toggled{
    max-height: 9999px;
    transition-timing-function: cubic-bezier(0.5, 0, 1, 0); 
    transition-delay: 0s;
}

参见示例: http : //jsfiddle.net/0hnjehjc/1/

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

好!我知道这个问题与互联网一样古老,但是我想我有一个解决方案,后来我将其变成了名为mutant-transition插件 。每当DOM发生更改时,我的解决方案都会为跟踪元素设置style=""属性。最终结果是,您可以在转换中使用优质的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 +中转换。

小提琴!

我一直使用的解决方案是先淡出,然后缩小font-sizepaddingmargin值。它看起来不像擦拭纸,但没有静态的heightmax-height

工作示例:

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

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

/* reveal */
#menu:hover #list {
    /* unshrink, then fade in */
    transition: font-size .25s,
                margin .25s,
                padding .25s,
                opacity .5s .25s;
}
<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>

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

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;
}

好吧,所以我想我想出了一个非常简单的答案... no 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>

小型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; }
   }
}

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

没有硬编码的值。

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

查看有关某个相关问题的帖子

基本上,从height: 0px;开始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;
  }
}

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

密码笔

几乎没有提到Element.scrollHeight属性,该属性在这里可能有用,但仍可以与纯CSS过渡一起使用。该属性始终包含元素的“完整”高度,无论其内容是否由于高度折叠(例如, height: 0 )而溢出以及如何溢出。

这样,对于height: 0height: 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例如, overflow: auto )。另外,由于基于max-height的解决方案破坏了缓动和计时,因为使用的高度可能比max-height达到9999px所需要的时间要早​​得多。随着屏幕分辨率的提高,像9999px这样的像素长度在我的口中留下了不良的味道。我认为,这种特殊的解决方案以一种优雅的方式解决了这个问题。

最后,这里希望CSS的未来修订版能够满足作者的要求,使他们更加优雅地做这些事情-重新审视“ compute” vs“ used”和“ resolved”值的概念,并考虑是否应将过渡应用于计算值。值,包括具有widthheight过渡(目前有一些特殊处理)。

而不是高度,您可以使用下面的方法

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

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

.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并以足够快的速度转换它,而不是转换高度,max-height或scaleY()等,以使高度转换为所需的高度。当前无法使用CSS将实际高度转换为自动,但是可以转换其中的内容,因此可以转换字体大小。

  • 注意-Codepen中有JavaScript,但唯一的目的是单击时添加/删除CSS类的手风琴。这可以通过隐藏的单选按钮完成,但是我并没有专注于此,只是高度转换。

发布此帖子时,已经有30多个答案,但我觉得我的答案比jake早已接受的答案有所改善。

我不满足于仅使用max-height和CSS3过渡所引起的问题,因为正如许多评论者所指出的,您必须将max-height值设置为非常接近实际高度,否则会出现延迟。有关该问题的示例,请参见此JSFiddle

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

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

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

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

应该将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>

我知道这是这个问题的答案,但我认为这是值得的,所以就去吧。这是具有以下属性的纯CSS解决方案:

  • 一开始没有延迟,过渡也不会尽早停止。在两个方向(展开和折叠)中,如果您在CSS中指定了300ms的过渡持续时间,则过渡需要300ms的时间。
  • 它正在转换实际高度(与transform: scaleY(0) ),因此,如果可折叠元素后面有内容,则它做对了。
  • 虽然(像其他的解决方案), 神奇的号码(如“选择一个长度比你的框永远将会是更高的”),这不是致命的,如果你的假设最终被错。在这种情况下,过渡效果可能看起来并不惊人,但是在过渡之前和之后,这都不成问题:在扩展状态( height: auto )状态下,整个内容始终具有正确的高度(例如,如果您选择max-height过低)。在折叠状态下,高度应为零。

演示版

这是一个具有三个可折叠元素的演示,它们的高度都不同,并且都使用相同的CSS。您可能要在单击“运行摘要”后单击“整页”。请注意,JavaScript仅切换collapsed CSS类,不涉及任何度量。 (您可以使用复选框或:target来进行完全没有任何JavaScript的演示,)。还要注意,CSS中负责过渡的部分非常短,而HTML仅需要一个附加的wrapper元素。

$(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像素的框,则margin-bottom: -2000px不会隐藏所有内容-即使在折叠的情况下也会有可见的东西。这是一个较小的修复程序,我们将在以后进行。
  • 例如,如果实际的框高为1000像素,并且过渡的长度为300ms,则可见过渡在大约150ms后已经结束(或者在相反的方向上延迟了150ms)。

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

这是一个动画,显示了如何将底部边距过渡与持续时间相等的最小高度过渡组合在一起,从而为我们提供了从全高到持续时间相同的零高度的组合过渡。

如上所述的动画

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

对于我的演示,我将50px设置为最小最小高度的上限。这是第二个魔术数字,它应该低于盒子的高度。 50px也很合理;您似乎不太可能经常想使一个可折叠的元素起初甚至不超过50像素。

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

还有两个问题需要解决:

  1. 从上方的角度来看,高度超过2000像素的框在折叠状态下并未完全隐藏,
  2. 另一个问题是,在非隐藏情况下,即使不运行过渡,小于50像素高度的框也会过高,因为最小高度将其保持在50像素。

我们通过为容器元素提供max-height: 0在折叠的情况下为0s 0.3s过渡为0s 0.3s解决第一个问题。这意味着它并不是真正的过渡,但是max-height会延迟应用;它仅在过渡结束后才适用。为了使它正常工作,我们还需要为相反的,未折叠的状态选择一个数值max-height 。但是与2000px情况不同的是,选择太大的数字会影响过渡的质量,在这种情况下,这实际上并不重要。因此,我们可以选择一个很高的数字,以至于我们知道没有一个高度会接近这个数字。我选了一百万像素。如果您觉得可能需要支持超过一百万像素的高度的内容,则1)对不起,2)仅添加两个零。

第二个问题是为什么我们实际上没有使用min-height来进行最小高度转换。相反,容器中有一个::after伪元素,其height从50px过渡到零。这与min-height具有相同的效果:不会让容器缩小到伪元素当前具有的任何高度以下。但是,因为我们使用的是height而不是min-height ,所以我们现在可以使用max-height (再次应用延迟)将过渡结束后将伪元素的实际高度设置为零,从而确保至少在过渡,即使是很小的元素也具有正确的高度。由于min-heightmax-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过渡这一事实之外,这是一个毫无意义的练习。

Flexbox解决方案

优点:

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

缺点:

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

它的工作方式是始终具有flex-basis:在具有内容的元素上自动放置,然后过渡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小提琴

这对我有效:

  .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和样式组件): https ://codesandbox.io/s/ol3kl56q9q

我了解这个问题要求没有JavaScript的解决方案。但是对于那些感兴趣的人,这里是我的解决方案,仅使用少量JS。

好的,因此默认情况下高度将更改的元素的CSS设置为height: 0;当打开height: auto; 。它还具有transition: height .25s ease-out; 。但是,当然,问题在于它不会向高处过渡height: auto;

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

打开时,我添加了一个transitionend事件侦听器,该侦听器将只运行一次,然后删除将其内联样式设置为height: auto;的内联样式height: auto;这将允许元素在必要时调整大小,例如在这个带有子菜单https://codepen.io/ninjabonsai/pen/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>

对于没有max-height延迟动画的max-height动画的纯CSS解决方案,我会考虑在悬停时设置一个合理的max-height ,大约在500px左右,或者比您大多数元素的高度大约或稍大一些想要动画,并通过以0.5秒的延迟完成动画后将overflow-y设置为auto来滚动更大的内容。

然后,将过渡时间设置为0.3s左右(如果扩展最终会在页面上移动其他内容,则将过渡时间设置为稍微慢一些),并在打开时使用指数缓和立方贝塞尔曲线,并使用缓入立方贝塞尔曲线并且在关闭时更快一些(例如0.15秒),因为当人们从页面中删除某些内容时,他们通常并不真正希望等待观察它消失。

这些快速动画仍然对用户可见,并且最大程度地减少了导致您的页面变慢的最大高度延迟的影响。

代码看起来像这样:

#child0 {
  max-height: 0;
  overflow-y: hidden;
  background-color: #dedede;
  -webkit-transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
  -moz-transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
  -o-transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
  transition: max-height 0.15s cubic-bezier(0.7, 0, 1, 0.5), overflow-y 0s linear 0s;
}
#parent0:hover #child0 {
  max-height: 500px;
  overflow-y: auto;
  -webkit-transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
  -moz-transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
  -o-transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
  transition: max-height 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), overflow-y 0s linear 0.3s;
}

我不愿意发布此消息,因为它违反了问题的“无JavaScript”部分;但无论如何都会这样做,因为它扩展到了yScale答案https://stackoverflow.com/a/17260048/6691,因此可以认为是该答案的“实际上并未删除空间”问题的解决方案,当禁用JavaScript时,基本比例效果仍然有效。

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

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

基本上,我们使用requestAnimationFrame来监视已应用scaleY转换后的结果框的高度( el.getBoundingClientRect().height获得此值),然后在元素上施加负margin-bottom以“吃掉”空白空间。

这适用于任何转换效果。我还添加了带有透视图的rotateX演示。

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

我已经使用以下文章的技术2:transform:scaleY()满足了没有JS的要求。

https://css-tricks.com/using-css-transitions-auto-dimensions/

.wrapper ul {
  transform: scaleY(0);
  transform-origin: top;
  transition: 0.3s;
  height: 0;
}

.wrapper:hover ul {
  height: auto;
  transform: scaleY(1)
}
<div class="wrapper">
  <h2>List</h2>
  <ul>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
  </ul>
</div>

我发布了一些JavaScript的答案,并被否决了,因此感到恼火并再次尝试,仅使用CSS破解了它!

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

这样做的结果是,我们仅使用CSS即可进行高效的过渡,并且可以使用一个过渡功能来平稳地实现过渡。圣杯!

当然,还有一个缺点!我不知道如何控制内容被截断的宽度( overflow:hidden );由于存在底部填充漏洞,因此宽度和高度密切相关。也许有办法,所以会回到正题。

https://jsfiddle.net/EoghanM/n1rp3zb4/28/

body {
  padding: 1em;
}

.trigger {
  font-weight: bold;
}

/* .expander is there for float clearing purposes only */
.expander::after {
  content: '';
  display: table;
  clear: both;
}

.outer {
  float: left; /* purpose: shrink to fit content */
  border: 1px solid green;
  overflow: hidden;
}

.inner {
  transition: padding-bottom 0.3s ease-in-out;  /* or whatever crazy transition function you can come up with! */
  padding-bottom: 0%;  /* percentage padding is defined in terms of width. The width at this level is equal to the height of the content */
  height: 0;

  /* unfortunately, change of writing mode has other bad effects like orientation of cursor */
  writing-mode: vertical-rl;
  cursor: default; /* don't want the vertical-text (sideways I-beam) */
  transform: rotate(-90deg) translateX(-100%);  /* undo writing mode */
  transform-origin: 0 0;
  margin: 0;  /* left/right margins here will add to height */
}

.inner > div { white-space: nowrap; }

.expander:hover .inner,  /* to keep open when expanded */
.trigger:hover+.expander .inner {
  padding-bottom: 100%;
}
<div class="trigger">HoverMe</div>
<div class="expander">
  <div class="outer">
    <div class="inner">
      <div>First Item</div>
      <div>Content</div>
      <div>Content</div>
      <div>Content</div>
      <div>Long Content can't be wider than outer height unfortunately</div>
      <div>Last Item</div>
    </div>
  </div>
</div>
<div>
  after content</div>
</div>

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

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

  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>

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

您可以通过使用剪辑路径创建反向(折叠)动画来实现。

#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>

如果您正在使用React,我可以推荐react-animate-height

<AnimateHeight height={isOpen ? 'auto' : 0}>
  // your content goes here
</AnimateHeight>

我只是设置了<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。

正确的解决方案

scrollHeight

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

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

Related