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


当前回答

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

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

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

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>

其他回答

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

我使用了最大高度: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>

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

我对简单地使用最大高度和CSS3转换产生的问题并不满意,因为正如许多评论人士所指出的,你必须将最大高度值设置得非常接近实际高度,否则会延迟。有关该问题的示例,请参阅此JSFiddle。

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

这意味着同时使用了max-height和translateY:max-heith允许元素向下推它下面的元素,而translateY提供了我们想要的“即时”效果。最大高度的问题仍然存在,但其影响有所减弱。这意味着你可以为你的最大高度值设置一个更大的高度,而不用担心它。

总的好处是,在转换回(塌陷)时,用户可以立即看到translateY动画,因此最大高度需要多长时间并不重要。

解决方案为Fiddle

正文{字体系列:无衬线;}.切换{位置:相对;边框:2px实心#333;边界半径:3px;边距:5px;宽度:200px;}.切换标题{边距:0;填充:10px;背景色:#333;颜色:白色;文本对齐:居中;光标:指针;}.拨动高度{背景色:番茄;溢出:隐藏;过渡:最大高度。6s轻松;最大高度:0;}.tggle:悬停.tggle高度{最大高度:1000px;}.tggle转换{填充:5px;颜色:白色;转换:转换。4s轻松;变换:translateY(-100%);}.tggle:悬停.tggle变换{变换:translateY(0);}<div class=“toggle”><div class=“toggle header”>切换!</div><div class=“toggle height”><div class=“toggle transform”><p>内容</p><p>内容</p><p>内容</p><p>内容</p></div></div></div><div class=“toggle”><div class=“toggle header”>切换!</div><div class=“toggle height”><div class=“toggle transform”><p>内容</p><p>内容</p><p>内容</p><p>内容</p></div></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。

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

好的,因此默认情况下高度将更改的元素的css设置为height:0;打开高度时:自动;。它也有过渡:高度;。但当然,问题是它不会从高度转换到高度:自动;

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

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

关闭时,我会在下一个事件循环循环后立即使用setTimeout删除内联样式,而不会延迟。这意味着高度:自动;被临时覆盖,这允许转换回高度0;

const showHideElement=(元素,打开)=>{element.style.height=element.scrollHeight+“px”;element.classList.tggle(“打开”,打开);if(打开){element.addEventListener('transitionnend',()=>{element.style.removeProperty('height');}, {一次:真});}其他{window.setTimeout(()=>{element.style.removeProperty('height');});}}const menu=document.body.querySelector(“#menu”);const list=document.body.querySelector(“#menu>ul”)menu.addEventListener('useenter',()=>showHideElement(列表,true));menu.addEventListener('useleave',()=>showHideElement(list,false));#菜单>ul{高度:0;溢出:隐藏;背景色:#999;过渡:高度。25s缓和;}#菜单>ul.open{高度:自动;}<div id=“menu”><a>悬停我</a><ul><li>项目</li><li>项目</li><li>项目</li><li>项目</li><li>项目</li></ul></div>