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


当前回答

这是一个仅限CSS的解决方案,具有以下财产:

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

Demo

这里有一个演示,其中有三个可折叠的元素,它们都有不同的高度,都使用相同的CSS。您可能希望在单击“运行代码段”后单击“完整页面”。请注意,JavaScript仅切换折叠的CSS类,不涉及度量。(通过使用复选框或:target,您可以在完全没有JavaScript的情况下进行这个精确的演示)。还要注意,负责转换的CSS部分很短,HTML只需要一个额外的包装元素。

$(函数(){$(“.tggler”).click(函数(){$(this).next().tggleClass(“塌陷”);$(this).tggleClass(“已切换”);//这只会旋转展开器箭头});});.可折叠包装纸{显示:柔性;溢出:隐藏;}.可折叠包装:在之后{内容:“”;高度:50px;过渡:高度0.3s线性,最大高度0s 0.3s线性;最大高度:0px;}.可折叠{过渡:边缘底部0.3s立方bezier(0,0,0、1);边距底部:0;最大高度:1000000px;}.scollapsible-wrappercollapsed>.scollapsble{边距底部:-2000px;过渡:边缘底部0.3s立方bezier(1,0,1,1),能见度0s 0.3s,最大高度0s 0.3s;可见性:隐藏;最大高度:0;}.可折叠包装器.折叠:之后{高度:0;过渡:高度0.3s线性;最大高度:50px;}/*可折叠实现结束;下面的东西只是这个演示的样式*/#集装箱{显示:柔性;对齐项目:弹性开始;最大宽度:1000px;边距:0自动;} .菜单{边框:1px实心#ccc;方框阴影:0 1px 3px rgba(0,0,0,0.5);边距:20px;}.菜单项{显示:块;背景:线性梯度(到底部,#fff 0%,#eee 100%);边距:0;填充:1em;线高:1.3;}.可折叠.菜单项{左侧边框:2px实心#888;右边框:2px实心#888;背景:线性梯度(至底部,#eee 0%,#ddd 100%);}菜单项日志{背景:线性梯度(至底部,#aaa 0%,#888 100%);颜色:白色;光标:指针;}.menu item.tggler:之前{内容:“”;显示:块;左侧边框:8px纯白色;边框顶部:8px实心透明;边框底部:8px实心透明;宽度:0;高度:0;浮动:右侧;转变:转变0.3s缓和;}.menu item.tggler.toggled:之前{变换:旋转(90度);}正文{字体系列:无衬线;字体大小:14px;}*,*:之后{框大小调整:边框框;}<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”>涉及全息甲板的东西</div><div class=“menu item”>派遣一支客场球队</div><div class=“menu item toggler”>高级解决方案</div><div class=“可折叠包装器已折叠”><div class=“可折叠”><div class=“menu item”>单独的茶托</div><div class=“menu item”>派遣一支包括队长在内的客场球队(尽管Riker表示抗议)</div><div class=“menu item”>Ask Worf</div><div class=“menu item”>涉及19世纪卫斯理和全息甲板的东西</div><div class=“menu item”>向Q寻求帮助</div></div></div><div class=“menu item”>甜言蜜语外星人侵略者</div><div class=“menu item”>从辅助系统重新布线</div></div><div class=“menu”><div class=“menu item”>涉及全息甲板的东西</div><div class=“menu item”>派遣一支客场球队</div><div class=“menu item toggler”>高级解决方案</div><div class=“可折叠包装器已折叠”><div class=“可折叠”><div class=“menu item”>单独的茶托</div><div class=“menu item”>派出一支包括队长在内的客场球队(尽管Riker表示抗议)</div></div></div><div class=“menu item”>甜言蜜语外星人侵略者</div><div class=“menu item”>从辅助系统重新布线</div></div><div class=“menu”><div class=“menu item”>涉及全息甲板的东西</div><div class=“menu item”>派遣一支客场球队</div><div class=“menu item toggler”>高级解决方案</div><div class=“可折叠包装器已折叠”><div class=“可折叠”><div class=“menu item”>单独的茶托</div><div class=“menu item”>派出一支包括队长在内的客场球队(尽管Riker表示抗议)</div><div class=“menu item”>Ask Worf</div><div class=“menu item”>涉及19世纪卫斯理和全息甲板的东西</div><div class=“menu item”>向Q寻求帮助</div><div class=“menu item”>单独的茶托</div><div class=“menu item”>派遣一支包括队长在内的客场球队(尽管Riker表示抗议)</div><div class=“menu item”>Ask Worf</div><div class=“menu item”>涉及19世纪卫斯理和全息甲板的东西</div><div class=“menu item”>向Q寻求帮助</div></div></div><div class=“menu item”>甜言蜜语外星人侵略者</div><div class=“menu item”>从辅助系统重新布线</div></div></div>

它是如何工作的?

事实上,实现这一点涉及两个过渡。其中一个将边距底部从0px(展开状态)转换为-2000px(折叠状态)(类似于此答案)。这里的2000是第一个神奇的数字,它基于这样的假设,即你的盒子不会高于这个数字(2000像素似乎是一个合理的选择)。

单独使用保证金底部转换有两个问题:

如果你有一个高于2000像素的框,那么底部的边距:-2000px不会隐藏所有内容,即使在折叠的情况下也会有可见的内容。这是我们稍后要做的一个小修复。如果实际的框是1000像素高,并且你的过渡是300毫秒长,那么在大约150毫秒之后,可见的过渡已经结束(或者,在相反的方向上,延迟150毫秒开始)。

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

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

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

对于我的演示,我已经确定了50像素作为上限最小高度值。这是第二个神奇的数字,它应该低于盒子的高度。50px似乎也很合理;您似乎不太可能经常想要让一个元素在一开始甚至不到50像素高的情况下进行折叠。

正如您在动画中看到的,生成的过渡是连续的,但它是不可微分的——当最小高度等于由底部边距调整的全高度时,速度会突然变化。这在动画中非常明显,因为它对两个过渡都使用了线性计时函数,而且整个过渡非常缓慢。在实际情况下(我在顶部的演示),转换只需要300毫秒,而底部边缘转换不是线性的。我在这两种转换中都使用了很多不同的计时功能,而我最终使用的这些功能似乎最适合最广泛的情况。

还有两个问题需要解决:

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

我们通过给容器元素一个最大高度来解决第一个问题:在折叠的情况下为0,0到0.3s的过渡。这意味着这不是真正的过渡,但最大高度是有延迟的;它只在过渡结束后才适用。为了正确工作,我们还需要为相反的非折叠状态选择一个数值最大高度。但与2000px的情况不同,选取过大的数字会影响转换的质量,在这种情况下,这真的无关紧要。因此,我们可以选择一个高度如此之高的数字,我们知道任何高度都不会接近这个数字。我选了一百万像素。如果你觉得你可能需要支持超过100万像素的内容,那么1)对不起,2)只需添加几个零。

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

在Chrome(Win、Mac、Android、iOS)、Firefox(Win,Mac、Android)、Edge、IE11(除了我的演示中的flexbox布局问题,我没有调试)和Safari(Mac、iOS)中进行测试。说到flexbox,应该可以在不使用任何flexbox的情况下实现这一功能;事实上,我认为你可以在IE7中让几乎所有的东西都正常工作,除了你不会有CSS转换,这是一个毫无意义的练习。

其他回答

我能够做到这一点。我有一个.child和一个.parent div。子div完全符合父div的宽度/高度,具有绝对定位。然后设置平移属性的动画,将其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上指定一个高度,单位为px,%,或保留为auto。这个div然后在向下滑动时屏蔽掉.child div。

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

动画动画显示的是从0到100的字体大小(%)。什么?父级的已知字体大小。

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

对所有字体大小和行高使用%将em用于所有垂直方向(如高度、边距和顶部/底部填充等)如果将px用于垂直的内容(例如,边框顶部/底部),则在框关闭时应覆盖该内容(例如:边框顶部:0;边框底部:0;)

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

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

悬停版本:

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

#第页{字体大小:calc((35vw+65vh)/30);/*只是一些响应性设计作为奖励*/}#滑动轴承箱{背景色:#e8e8e8;可见性:隐藏;字号:0;/*从0到100%设置动画*/不透明度:0;/*可选的*/过渡:0.5s;}a#ahover:悬停~#slidebox{可见性:可见;字体大小:100%;/*从0到100%设置动画*/不透明度:1;/*可选的*/}a#ahover:not(:hover)~#slidebox*{边框顶部:0;边框底部:0;/*在这里放置任何以像素为单位的垂直线,在本例中为边框*/}a#按钮{显示:内联flex;对齐项目:居中;对齐内容:中心;位置:相对;宽度:20em;高度:3em;填充:0.5em;边框:2px实心#0080ff;边界半径:0.4em;背景色:#8fbfef;颜色:#404040;框大小调整:边框框;}#某种形式的{页边距:1em;边距底部:1em;填充:1 m 4 m 1 m 4 mm;背景色:#d8ffd8;边框:1px实心#888888;}#某种形式的输入{显示:内联块;框大小调整:边框框;字体大小:125%;填充:0.5em;宽度:50%;/*任何水平的都可以是px或%*/边界半径:0.4em;边框:1px纯红色;}<div id=page><a id=ahover href=“#”>悬停我</a><br>下面是滑动框:<div id=slidebox>我是幻灯片框的内容(第1行)<br>我是幻灯片框的内容(第2行)<br><a id=button href=“#”>我是幻灯片框中的某个按钮</a><br>我是幻灯片框的内容(第3行)<br>我是幻灯片框的内容(第4行)。<div id=someform>一个有表格的盒子<br><输入类型=文本值=“文本框”></div>我是幻灯片框的内容(第5行)<br>我是幻灯片框的内容(第6行)。</div>这是在盒子后面。</div>

类别更改版本:

https://jsfiddle.net/8xzsrfh6/

const switch_ele=文档.getElementById('aclass');switch_ele.addEventListener('click',函数(){const box_ele=文档.getElementById('slidebox');box_ele.className=box_ele_className=='显示'?'hide':'显示';},true);#第页{字体大小:calc((35vw+65vh)/30);/*只是一些响应性设计作为奖励*/}#滑动轴承箱{背景色:#e8e8e8;可见性:隐藏;字号:0;/*从0到100%设置动画*/不透明度:0;/*可选的*/转换:.5s;}#幻灯片放映{可见性:可见;字体大小:100%;/*从0到100%设置动画*/不透明度:1;/*可选的*/}#幻灯片隐藏*{边框顶部:0;边框底部:0;/*在这里放置任何以像素为单位的垂直线,在本例中为边框*/}a#按钮{显示:内联flex;对齐项目:居中;对齐内容:中心;位置:相对;宽度:20em;高度:3em;填充:0.5em;边框:2px实心#0080ff;边界半径:0.4em;背景色:#8fbfef;颜色:#404040;框大小调整:边框框;}#某种形式的{页边距:1em;边距底部:1em;填充:1 m 4 m 1 m 4 mm;背景色:#d8ffd8;边框:1px实心#888888;}#某种形式的输入{显示:内联块;框大小调整:边框框;字体大小:125%;填充:0.5em;宽度:50%;/*任何水平的都可以是px或%*/边界半径:0.4em;边框:1px纯红色;}<div id=page><a id=aclass href=“#”>开关类w/js</a><br>下面是滑动框:<div id=slidebox class=hide>我是幻灯片框的内容(第1行)<br>我是幻灯片框的内容(第2行)<br><a id=button href=“#”>我是幻灯片框中的某个按钮</a><br>我是幻灯片框的内容(第3行)<br>我是幻灯片框的内容(第4行)。<div id=someform>一个有表格的盒子<br><输入类型=文本值=“文本框”></div>我是幻灯片框的内容(第5行)<br>我是幻灯片框的内容(第6行)。</div>这是在盒子后面。</div>

这是一个仅限CSS的解决方案,具有以下财产:

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

Demo

这里有一个演示,其中有三个可折叠的元素,它们都有不同的高度,都使用相同的CSS。您可能希望在单击“运行代码段”后单击“完整页面”。请注意,JavaScript仅切换折叠的CSS类,不涉及度量。(通过使用复选框或:target,您可以在完全没有JavaScript的情况下进行这个精确的演示)。还要注意,负责转换的CSS部分很短,HTML只需要一个额外的包装元素。

$(函数(){$(“.tggler”).click(函数(){$(this).next().tggleClass(“塌陷”);$(this).tggleClass(“已切换”);//这只会旋转展开器箭头});});.可折叠包装纸{显示:柔性;溢出:隐藏;}.可折叠包装:在之后{内容:“”;高度:50px;过渡:高度0.3s线性,最大高度0s 0.3s线性;最大高度:0px;}.可折叠{过渡:边缘底部0.3s立方bezier(0,0,0、1);边距底部:0;最大高度:1000000px;}.scollapsible-wrappercollapsed>.scollapsble{边距底部:-2000px;过渡:边缘底部0.3s立方bezier(1,0,1,1),能见度0s 0.3s,最大高度0s 0.3s;可见性:隐藏;最大高度:0;}.可折叠包装器.折叠:之后{高度:0;过渡:高度0.3s线性;最大高度:50px;}/*可折叠实现结束;下面的东西只是这个演示的样式*/#集装箱{显示:柔性;对齐项目:弹性开始;最大宽度:1000px;边距:0自动;} .菜单{边框:1px实心#ccc;方框阴影:0 1px 3px rgba(0,0,0,0.5);边距:20px;}.菜单项{显示:块;背景:线性梯度(到底部,#fff 0%,#eee 100%);边距:0;填充:1em;线高:1.3;}.可折叠.菜单项{左侧边框:2px实心#888;右边框:2px实心#888;背景:线性梯度(至底部,#eee 0%,#ddd 100%);}菜单项日志{背景:线性梯度(至底部,#aaa 0%,#888 100%);颜色:白色;光标:指针;}.menu item.tggler:之前{内容:“”;显示:块;左侧边框:8px纯白色;边框顶部:8px实心透明;边框底部:8px实心透明;宽度:0;高度:0;浮动:右侧;转变:转变0.3s缓和;}.menu item.tggler.toggled:之前{变换:旋转(90度);}正文{字体系列:无衬线;字体大小:14px;}*,*:之后{框大小调整:边框框;}<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”>涉及全息甲板的东西</div><div class=“menu item”>派遣一支客场球队</div><div class=“menu item toggler”>高级解决方案</div><div class=“可折叠包装器已折叠”><div class=“可折叠”><div class=“menu item”>单独的茶托</div><div class=“menu item”>派遣一支包括队长在内的客场球队(尽管Riker表示抗议)</div><div class=“menu item”>Ask Worf</div><div class=“menu item”>涉及19世纪卫斯理和全息甲板的东西</div><div class=“menu item”>向Q寻求帮助</div></div></div><div class=“menu item”>甜言蜜语外星人侵略者</div><div class=“menu item”>从辅助系统重新布线</div></div><div class=“menu”><div class=“menu item”>涉及全息甲板的东西</div><div class=“menu item”>派遣一支客场球队</div><div class=“menu item toggler”>高级解决方案</div><div class=“可折叠包装器已折叠”><div class=“可折叠”><div class=“menu item”>单独的茶托</div><div class=“menu item”>派出一支包括队长在内的客场球队(尽管Riker表示抗议)</div></div></div><div class=“menu item”>甜言蜜语外星人侵略者</div><div class=“menu item”>从辅助系统重新布线</div></div><div class=“menu”><div class=“menu item”>涉及全息甲板的东西</div><div class=“menu item”>派遣一支客场球队</div><div class=“menu item toggler”>高级解决方案</div><div class=“可折叠包装器已折叠”><div class=“可折叠”><div class=“menu item”>单独的茶托</div><div class=“menu item”>派出一支包括队长在内的客场球队(尽管Riker表示抗议)</div><div class=“menu item”>Ask Worf</div><div class=“menu item”>涉及19世纪卫斯理和全息甲板的东西</div><div class=“menu item”>向Q寻求帮助</div><div class=“menu item”>单独的茶托</div><div class=“menu item”>派遣一支包括队长在内的客场球队(尽管Riker表示抗议)</div><div class=“menu item”>Ask Worf</div><div class=“menu item”>涉及19世纪卫斯理和全息甲板的东西</div><div class=“menu item”>向Q寻求帮助</div></div></div><div class=“menu item”>甜言蜜语外星人侵略者</div><div class=“menu item”>从辅助系统重新布线</div></div></div>

它是如何工作的?

事实上,实现这一点涉及两个过渡。其中一个将边距底部从0px(展开状态)转换为-2000px(折叠状态)(类似于此答案)。这里的2000是第一个神奇的数字,它基于这样的假设,即你的盒子不会高于这个数字(2000像素似乎是一个合理的选择)。

单独使用保证金底部转换有两个问题:

如果你有一个高于2000像素的框,那么底部的边距:-2000px不会隐藏所有内容,即使在折叠的情况下也会有可见的内容。这是我们稍后要做的一个小修复。如果实际的框是1000像素高,并且你的过渡是300毫秒长,那么在大约150毫秒之后,可见的过渡已经结束(或者,在相反的方向上,延迟150毫秒开始)。

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

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

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

对于我的演示,我已经确定了50像素作为上限最小高度值。这是第二个神奇的数字,它应该低于盒子的高度。50px似乎也很合理;您似乎不太可能经常想要让一个元素在一开始甚至不到50像素高的情况下进行折叠。

正如您在动画中看到的,生成的过渡是连续的,但它是不可微分的——当最小高度等于由底部边距调整的全高度时,速度会突然变化。这在动画中非常明显,因为它对两个过渡都使用了线性计时函数,而且整个过渡非常缓慢。在实际情况下(我在顶部的演示),转换只需要300毫秒,而底部边缘转换不是线性的。我在这两种转换中都使用了很多不同的计时功能,而我最终使用的这些功能似乎最适合最广泛的情况。

还有两个问题需要解决:

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

我们通过给容器元素一个最大高度来解决第一个问题:在折叠的情况下为0,0到0.3s的过渡。这意味着这不是真正的过渡,但最大高度是有延迟的;它只在过渡结束后才适用。为了正确工作,我们还需要为相反的非折叠状态选择一个数值最大高度。但与2000px的情况不同,选取过大的数字会影响转换的质量,在这种情况下,这真的无关紧要。因此,我们可以选择一个高度如此之高的数字,我们知道任何高度都不会接近这个数字。我选了一百万像素。如果你觉得你可能需要支持超过100万像素的内容,那么1)对不起,2)只需添加几个零。

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

在Chrome(Win、Mac、Android、iOS)、Firefox(Win,Mac、Android)、Edge、IE11(除了我的演示中的flexbox布局问题,我没有调试)和Safari(Mac、iOS)中进行测试。说到flexbox,应该可以在不使用任何flexbox的情况下实现这一功能;事实上,我认为你可以在IE7中让几乎所有的东西都正常工作,除了你不会有CSS转换,这是一个毫无意义的练习。

杰克对最大高度动画化的回答很好,但我发现设置大的最大高度所导致的延迟很烦人。

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

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

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

js部分只是点击,对于纯css解决方案,可以用:hover或checkbox替换。

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

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

这是结果

[…document.querySelectorAll('.ab')].forEach(包装器=>{wrapper.addEventListener('click',函数(){this.classList.tggle('active');});});* {边距:0;框大小调整:边框框;}.c文件{溢出:隐藏;}.个项目{宽度:100%;可见性:隐藏;最大高度:0;边距底部:-2000px;-webkit过渡:边缘0.6s立方bezier(1,0,1,1),最大高度0s 0.6s线性,可见性0s 0.6s直线;过渡:边缘0.6s立方贝塞尔(1,0,1,1),最大高度0.6s线性,可见性0.6s线性;}.项>*{填充:1rem;背景色:#ddd;-webkit过渡:背景色0.6s轻松;过渡:背景色0.6s轻松;}.items>*:悬停{背景色:#eee;}.ab文件{填充:1rem;光标:指针;背景:#eee;}.ab活动+.c.项目{最大高度:2000px;边距底部:0;可见性:可见;-webkit过渡:最大高度0.6s立方bezier(1,0,1,1);过渡:最大高度0.6s立方bezier(1,0,1,1);}下拉列表{右边距:1rem;}.包装器{显示:-webkit框;显示:柔性;}<div class=“wrapper”><div class=“下拉列表”><div class=“ab”>仅文本</div><div class=“ab”>仅文本</div><div class=“ab”>下拉列表</div><div class=“c”><div class=“items”><p>项目</p><p>项目</p><p>项目asl;dk l;卡斯尔;d sa;lk语言</p><p>项目sal;千分之三</p><p>项目</p></div></div><div class=“ab”>仅文本</div><div class=“ab”>仅文本</div></div><div class=“下拉列表”><div class=“ab”>下拉列表</div><div class=“c”><div class=“items”><p>项目</p><p>项目</p><p>项目</p><p>项目</p><p>项目</p><p>项目</p><p>项目</p><p>项目</p><p>项目</p><p>项目</p><p>项目</p></div></div><div class=“ab”>text</div></div><div class=“下拉列表”><div class=“ab”>占位符</div><div class=“ab”>下拉列表</div><div class=“c”><div class=“items”><p>项目</p><p>项目</p></div></div><div class=“ab”>占位符</div><div class=“ab”>占位符</div><div class=“ab”>占位符</div></div></div><h1>要推送的文本</h1>