前言
在实现鼠标移入某个元素,展开某个列表的功能时,可能列表的长度是不固定的,就无法通过写死高度去实现过渡效果。
公共样式
html
<div class="button">
<div class="text">Hover me</div>
<div class="list">
<div class="content">
Change, a constant and inevitable force in our lives, often brings a mix
of excitement, fear, and uncertainty. It's the engine of progress,
pushing us out of our comfort zones and into new territories. While it
can be daunting, embracing change can lead to personal growth and new
opportunities.
</div>
</div>
</div>
css
.button {
padding: 10px;
width: fit-content;
background: aquamarine;
border-radius: 10px;
}
.button:hover .list {
visibility: visible;
}
.list {
position: absolute;
visibility: hidden;
width: 200px;
background: antiquewhite;
border-radius: 10px;
}
尝试 height: auto
那如果 hover 后把列表的高度改为 auto 呢,代码如下:
css
.button:hover .list {
height: auto;
}
.list {
overflow: hidden;
height: 0;
transition: 0.3s;
}
实现效果:
可以看到没出现过渡效果,这是因为过渡 transition
只对于属性值是数值的才有效,显然 auto
并不是数值类型。
尝试 max-height
将 height
改为 max-height
css
.button:hover .list {
max-height: 800px;
}
.list {
overflow: hidden;
max-height: 0;
transition: 0.3s;
}
过渡的效果和预想的不太一样,速度有点快。因为过渡是按照设置的 800px
去计算的。
尝试 transform: scale()
css
.button:hover .list {
transform: scaleY(1);
}
.list {
overflow: hidden;
transform: scaleY(0);
transform-origin: top;
transition: 0.3s;
}
可以看到里面的内容也被压缩了,效果不太好。
尝试 grid 布局
css
.button:hover .list {
grid-template-rows: 1fr;
}
.list {
display: grid;
grid-template-rows: 0fr;
transition: 0.3s;
}
.list .content {
overflow: hidden;
}
使用grid
可以完美的实现想要的效果,虽然主流的浏览器都已经支持,但在实际使用中还是要注意下兼容性问题。
使用 js
js
const button = document.querySelector(".button");
const list = document.querySelector(".list");
button.addEventListener("mouseover", () => {
list.style.height = "auto";
const height = list.clientHeight;
list.style.transition = "0.3s";
list.style.height = 0;
list.clientHeight; // 强制回流,让 list 高度变为 0
list.style.height = `${height}px`;
});
button.addEventListener("mouseout", () => {
list.style.height = 0;
});
实现原理: FLIP
实现思路:
- 鼠标移入按钮时,先把
list
的高度改为auto
,让其自动计算高度。 - 记录计算出的高度,这里使用了
clientHeight
会使浏览器回流,虽然此时浏览器还没有重绘,但可以获取到list
的height
为auto
时的高度。 - 加入过渡效果,这里可以写在css里。设置
list
高度为0
。 - 读取
list
的clientHeight
使浏览器回流,让list
的实际高度为0
。 - 设置
list
的高度为之前记录的值。