我正在尝试使用CSS转换制作一个<ul>幻灯片。

<ul>开始于高度:0;。悬停时,高度设置为height:auto;。然而,这导致它简单地出现,

如果我从高度做:40px;至高度:自动;,那么它将向上滑动到高度:0;,然后突然跳到正确的高度。

如果不使用JavaScript,我怎么能做到这一点?

#子0{高度:0;溢出:隐藏;背景色:#dedede;-moz过渡:高度1s容易;-webkit过渡:高度1s轻松;-o过渡:高度1s容易;过渡:高度1s;}#parent0:悬停#child0{高度:自动;}#孩子40{高度:40px;溢出:隐藏;背景色:#dedede;-moz过渡:高度1s容易;-webkit过渡:高度1s轻松;-o过渡:高度1s容易;过渡:高度1s;}#parent40:悬停#child40{高度:自动;}h1小时{字号:粗体;}两个CSS片段之间的唯一区别是一个高度为0,另一个高度是40。<小时><div id=“parent0”><h1>将我悬停(高度:0)</h1><div id=“child0”>一些内容<br>一些内容<br>一些内容<br>一些内容<br>一些内容<br>一些内容<br></div></div><小时><div id=“parent40”><h1>将我悬停(高度:40)</h1><div id=“child40”>一些内容<br>一些内容<br>一些内容<br>一些内容<br>一些内容<br>一些内容<br></div></div>


当前回答

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

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

parent{border top:#999 1px solid;}h1{margin:.5rem;字体大小:1.3rem}.儿童{高度:0;溢出:隐藏;背景色:#dedede;过渡:填充。2s易进易出,不透明度。2s容易进易出;填充:0.5雷姆;不透明度:0;}.childre::之前,.childres::之后{content:“”;显示:块;}.children::在{margin-top:-2rem;}之前.children::在{margin-bottom:-2rem;}之后.父级:悬停.子级{高度:自动;不透明度:1;衬垫:2.5雷姆。5雷姆;/*0.5+abs(-2),确保低于预期最小高度*/}<div class=“parent”><h1>将我悬停</h1><div class=“children”>一些内容<br>一些内容<br>一些内容<br>一些内容<br>一些内容<br>一些内容<br></div></div><div class=“parent”><h1>将我悬停(长内容)</h1><div class=“children”>一些内容<br>部分内容<br>部分内容<br>部分内容<br>部分内容<br>部分内容<br>部分内容<br>部分内容<br>部分内容<br>部分内容<br>部分内容<br></div></div><div class=“parent”><h1>悬停我(简短内容)</h1><div class=“children”>一些内容<br>一些内容<br>一些内容<br></div></div>

其他回答

要从任何起始高度(包括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文件放到页面中:

/*** Code for height: auto; transitioning ***/

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

/*** Code for DEMO ***/

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

下面是我刚刚与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 }

您应该改用scaleY。

上一页{背景色:#eee;变换:缩放Y(0);变换原点:顶部;转变:转变0.26s;}p: 悬停~ul{变换:缩放Y(1);}<p>将此悬停</p><ul><li>咖啡</li><li>茶</li><li>牛奶</li></ul>

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

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

上一页{剪辑:矩形(自动,自动,0,自动);位置:绝对;边距:-1rem 0;衬垫:.5rem;颜色:白色;背景色:rgba(0、0、0和0.8);过渡特性:剪辑;过渡时间:0.5s;过渡时间函数:立方贝塞尔(0.175、0.885、0.32、1.275);}h3:悬停~ul,h3:活性~ul,ul:悬停{剪辑:矩形(自动,自动,10rem,自动);}<h3>悬停在此处</h3><ul><li>此列表</li><li>被剪裁</li><li>剪辑过渡</li><li>将显示它</li></ul><p>一些文本。。。</p>

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

我认为最好的方法是使用最大高度,但仅限于表演阶段。不要在隐藏时使用任何动画。在大多数情况下,这并不重要。

最大高度应该设置为一个非常大的值,以确保任何内容都适合。可以使用过渡持续时间控制动画速度(速度=最大高度/持续时间)。速度不取决于内容的大小。显示整个内容所需的时间将取决于其大小。

document.querySelector(“button”).addEventListener(“点击”,函数(){document.querySelector(“div”).classList.tggle(“hide”);})分区{最大高度:20000px;过渡:最大高度3000ms;overflow-y:隐藏;}.隐藏{最大高度:0;过渡:无;}<button>切换</button><div class=“hide”>Lorem ipsum dolor坐amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。Lorem ipsum dolor sit amet,ius solet dignissim honestatis ad Mea quem tibque intellegat te。内窥镜检查和检查。所有人都知道领事馆。Vix novum primis称呼no,eam denique sensius et,他的ipsum senserit ne。</div>

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

填充底部:100%“hack”,其中百分比是根据元素的当前宽度定义的。有关此技术的更多信息。浮动收缩包装,(需要额外的div来应用浮动清除黑客)非语义使用https://caniuse.com/#feat=css-编写模式和一些转换来撤销它(这允许在垂直上下文中使用上面的填充黑客)

结果是,我们只使用CSS实现了高性能的转换,并使用一个转换函数来平滑地实现转换;圣杯!

当然,这也有缺点!我无法确定如何控制内容被截断的宽度(溢出:隐藏);由于衬垫底部的裂缝,宽度和高度密切相关。不过,也许有办法,所以我们会回到过去。

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

正文{填充:1em;}.触发器{字号:粗体;}/*.扩展器仅用于浮动清除*/.扩展器::之后{内容:“”;显示:表格;清晰:两者都有;}.外部{float:左;/*目的:收缩以适应内容*/边框:1px实心绿色;溢出:隐藏;}.内部{过渡:填充底部0.3s,方便进出;/*或者你能想出的任何疯狂的转换函数*/底部填充:0%;/*填充百分比是根据宽度定义的。此级别的宽度等于内容的高度*/高度:0;/*不幸的是,书写模式的改变还有其他的不良影响,比如光标的方向*/写入模式:垂直rl;光标:默认值;/*不需要垂直文本(横向工字梁)*/变换:旋转(-90度)平移X(-100%);/*撤消写入模式*/变换原点:0 0;边距:0;/*此处的左/右边距将增加高度*/}.inter>div{white-space:nowrap;}.extender:hover.intern,/*在展开时保持打开*/.t触发器:悬停+扩展器.内部{填充底部:100%;}<div class=“trigger”>HoverMe</div><div class=“扩展器”><div class=“outer”><div class=“inner”><div>第一项</div><div>内容</div><div>内容</div><div>内容</div><div>长内容不能宽于外部高度,不幸的是</div><div>最后一项</div></div></div></div><div>在内容之后</div></div>