CSS如何实现自适应高度的展开收起过渡动画效果?
前言
想要实现一个可以展开收起的效果并不难,直接用display: none;就能完成,但这种方法并不能实现过渡动画效果,想要实现过渡效果必须是属性值的变化,比如height从0到自身最大高度,除了用js计算元素的最大高度实现以外,以下列举了几种使用极少的CSS实现的方案。
一、最大高度:max-height(不推荐)
非常简单,但过渡动画不自然,过渡效果依赖于
max-height的最大值,因为不知道元素的高度所以这个值一般写的很大,这就导致速度曲线无法把控,看着很别扭。

<button>hover me</button>
<div class="wrapper">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta earum est eos quod dolorem ex culpa aliquid laboriosam! Iure ipsa deleniti velit. Magni quisquam, vel earum similique architecto deserunt reiciendis.
</div>
<style>
.wrapper {
width: 200px;
transition: 1s;
background-color: aqua;
max-height: 0;
overflow: hidden;
}
button:hover~.wrapper {
max-height: 1000px;
}
</style>
二、纵向缩放:scaleY(推荐)
比较简单,但会导致里面的内容被压缩,不在意这个的话效果还行。
注意:此方法收起状态下还是会占用页面空间!可以在下方添加元素测试。

<button>hover me</button>
<div class="wrapper">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta earum est eos quod dolorem ex culpa aliquid laboriosam! Iure ipsa deleniti velit. Magni quisquam, vel earum similique architecto deserunt reiciendis.
</div>
<style>
.wrapper {
width: 200px;
transition: 1s;
background-color: aqua;
transform: scaleY(0);
transform-origin: top;
}
button:hover~.wrapper {
transform: scaleY(1);
}
</style>
三、裁剪:clip-path(推荐)
过渡效果比较完美,这种方法灵活性特别高,可以用来创建多种剪裁效果,不限于简单的矩形区域。通过
clip-path的各种形状(如圆形、椭圆形、多边形等),可以实现更丰富的视觉效果,下面会给出一个案例仅供参考。
注意:此方法收起状态下还是会占用页面空间!可以在下方添加元素测试。

<button>hover me</button>
<div class="wrapper">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta earum est eos quod dolorem ex culpa aliquid laboriosam! Iure ipsa deleniti velit. Magni quisquam, vel earum similique architecto deserunt reiciendis.
</div>
<style>
.wrapper {
width: 200px;
background-color: aqua;
transition: 1s;
clip-path: inset(0 0 100% 0);
}
button:hover~.wrapper {
clip-path: inset(0 0 0 0);
}
</style>
.wrapper的clip-path: inset(0 0 100% 0);表示从顶部开始剪裁,剪裁到元素的 100% 高度,因此内容完全不可见。- 当按钮被悬停时,
.wrapper的clip-path变为inset(0 0 0 0);,即不剪裁任何内容,内容完全显示。

四、网格布局:grid-template-rows(推荐)
过渡效果和
clip-path一样比较完美,一般人想不到这个方法,但兼容性不太好,而且写法上稍微有点复杂。

<button>hover me</button>
<div class="wrapper">
<div class="detail">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta earum est eos quod dolorem ex culpa aliquid laboriosam! Iure ipsa deleniti velit. Magni quisquam, vel earum similique architecto deserunt reiciendis.
</div>
</div>
<style>
.wrapper {
width: 200px;
display: grid;
grid-template-rows: 0fr;
transition: 1s;
background-color: aqua;
overflow: hidden;
}
.detail {
min-height: 0;
}
button:hover~.wrapper {
grid-template-rows: 1fr;
}
</style>
对于网格布局这种实现方法容易疑惑的地方
这里重点说一下最后一种用网格布局实现的过渡动画效果是怎么实现的。
不知道当你看到最后一种方法有没有下面几个疑惑,为什么要这样写?究竟起到什么作用?这段代码第一眼看上去感觉不难,但是如果只让用grid-template-rows: 0fr;实现,在没看过这段代码的话还真的没那么容易写出来。
- 为什么要在内容区包裹一层
.detail?能不能不写这一层div? - 为什么
.detail样式中写min-height: 0;?作用是什么?
至于为什么要在.detail写min-height: 0;,解释如下:
-
默认行为:
- 默认情况下,CSS 中的
min-height属性为auto,这意味着元素的最小高度是根据其内容的高度自动计算的。 - 在您的代码中,
wrapper类的div元素使用grid-template-rows: 0fr;来将其高度设置为 0,这本质上是希望将detail元素的高度也设置为 0。
- 默认情况下,CSS 中的
-
overflow和min-height的交互:- 当
wrapper的高度被设置为 0 时,overflow: hidden;确保内容不可见。然而,detail元素的内容会尝试撑开这个元素。 - 由于
min-height默认是auto,它不会强制内容被压缩到高度为 0,所以内容会溢出,导致grid-template-rows: 0fr;不生效。
- 当
-
min-height: 0;的作用:- 设置
min-height: 0;强制detail元素可以缩小到高度为 0,确保wrapper的高度设置生效,从而实现内容完全被隐藏的效果。
- 设置
其实在写min-height: 0;之前我用的是overflow: hidden;,也能达到效果,不过有点瑕疵,像这样

<button>hover me</button>
<div class="wrapper">
<div class="detail">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dicta earum est eos quod dolorem ex culpa aliquid laboriosam! Iure ipsa deleniti velit. Magni quisquam, vel earum similique architecto deserunt reiciendis.
</div>
</div>
<style>
.wrapper {
width: 200px;
display: grid;
grid-template-rows: 0fr;
transition: 1s;
background-color: aqua;
}
.detail {
overflow: hidden;
}
button:hover~.wrapper {
grid-template-rows: 1fr;
}
</style>
代码如上述所示!不知道有没有看出来和上面min-height: 0;写法的区别,就是鼠标刚移到按钮上的时候过渡动画背景色是盖住一部分文字的,直到最下面才完全消失,这个具体原因是因为 overflow: hidden; 的行为和 min-height 的默认值相互作用的不同导致的。
主要问题分析
-
.wrapper的高度:grid-template-rows: 0fr;将.wrapper的高度设置为 0。
-
.detail的高度:- 默认情况下,
.detail的高度由其内容决定,且min-height是auto。
- 默认情况下,
-
overflow: hidden;的位置:- 将
overflow: hidden;移到.detail类上,虽然可以隐藏超出的内容,但.detail的内容会尝试占据它所需要的高度,这会影响.wrapper的高度设置。
- 将
原因详解
- 在第一版代码中,
overflow: hidden;被设置在.wrapper上,这样即使.detail内容再多,也不会撑开.wrapper。 min-height: 0;被设置在.detail上,这确保了.detail可以缩小到高度为 0。
在最新的代码中:
.detail的overflow: hidden;会隐藏超出的内容,但是.wrapper的高度会被.detail的内容撑开,因为min-height默认是auto。- 因此,
.wrapper无法保持高度为 0,导致布局和效果不一样。
转载自:https://juejin.cn/post/7381472292427563045