实现高度过渡
在工作中有时候会遇到点击实现Collapse折叠效果,而折叠的元素高度可能不固定的,使用height: 0
到height: auto
的方法是行不通的,因为一个值从数字变为非数字是不能使用过渡效果的,要实现该效果可使用其他方法。
html
<div id="root">
<h1>元素高度过渡效果(通过max-height实现)</h1>
<button class="btn">hover me</button>
<div class="parent">
<div class="inner">
三十六计的顺序是:
第1套胜战计,瞒天过海、 围魏救赵、借刀杀人、以逸待劳、趁火打劫、声东击西。
第2套敌战计,无中生有、暗渡陈仓、隔岸观火、笑里藏刀、李代桃僵、顺手牵羊。
第3套攻战计,打草惊蛇、借尸还魂、调虎离山、欲擒故纵、抛砖引玉、擒贼擒王。
第4套混战计,釜底抽薪、混水摸鱼、金蝉脱壳、关门捉贼、远交近攻、假道伐虢、
第5套并战计,偷梁换柱、指桑骂槐、假痴不颠、上楼抽梯、虚张声势、反客为主。
第6套败战计,美人计、空城计、反间计、苦肉计、连环计、走为上策。
</div>
</div>
<div>Footer</div>
</div>
max-height
- 点击max-height查看效果
可以对需要折叠的元素设置max-height
来实现过渡,例如从max-height: 0
到max-height: 1000px
,最终设置的max-height只要比该元素实际高度大就可以。
WARNING
这种方法会有一个问题,就是元素展开和收起的效果不一致,因为有一段时间会作用于max-height
减去折叠元素实际高度
的折叠,设置的max-height - 元素实际高度
越大,过渡差异越明显
css
.parent {
overflow: hidden;
max-height: 0;
transition: max-height 2s linear;
}
.btn:hover + .parent {
max-height: 1200px;
}
效果如下:
可以看到元素收起会比展开时慢了一点,效果不一致
scale
- 点击scale查看效果
css
.parent {
transform: scaleY(0);
transform-origin: top center;
transition: .5s linear;
}
.btn:hover + .parent {
transform: scaleY(1);
}
这种方法会使文字有拉伸效果,而且不做其他处理的话,未展开时,还占据了布局空间
效果如下:
grid
- 点击grid查看效果
可以通过grid布局来时间,通过设置元素的grid-template-rows
属性从0fr
到1fr
切换实现
html
<div id="root">
<h1>元素高度过渡效果(通过grid实现)</h1>
<button class="btn">hover me</button>
<div class="parent">
<div class="child">
<div class="inner">
三十六计的顺序是:
第1套胜战计,瞒天过海、 围魏救赵、借刀杀人、以逸待劳、趁火打劫、声东击西。
第2套敌战计,无中生有、暗渡陈仓、隔岸观火、笑里藏刀、李代桃僵、顺手牵羊。
第3套攻战计,打草惊蛇、借尸还魂、调虎离山、欲擒故纵、抛砖引玉、擒贼擒王。
第4套混战计,釜底抽薪、混水摸鱼、金蝉脱壳、关门捉贼、远交近攻、假道伐虢、
第5套并战计,偷梁换柱、指桑骂槐、假痴不颠、上楼抽梯、虚张声势、反客为主。
第6套败战计,美人计、空城计、反间计、苦肉计、连环计、走为上策。
</div>
</div>
</div>
<div>Footer</div>
</div>
css
.parent {
display: grid;
grid-template-rows: 0fr;
transition: .5s linear;
}
.btn:hover + .parent {
grid-template-rows: 1fr;
}
.child {
overflow: hidden;
}
效果如下:
使用js+css来实现
- 点击use-js查看效果
该方法的原理如下:
需要展开时先设置元素
height: auto
,这时元素就有实际高度。然后去获取元素的实际高度
先将元素高度设置为0,然后在设置为上一步获取的实际高度,这样高度就是准确值直接的切换,可以有过渡效果
TIP
该方法的兼容性最好
将元素高度设置为0后,一定要触发一次
重绘
,不然样式设置会被优化掉,不会有过渡效果
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./index.css">
<title>通过js+css实现</title>
<style>
.parent {
height: 0;
overflow: hidden;
transition: .5s linear;
}
</style>
</head>
<body>
<div id="root">
<h1>元素高度过渡效果(通过js+css实现)</h1>
<button class="btn">hover me</button>
<div class="parent">
<div class="inner">
三十六计的顺序是:
第1套胜战计,瞒天过海、 围魏救赵、借刀杀人、以逸待劳、趁火打劫、声东击西。
第2套敌战计,无中生有、暗渡陈仓、隔岸观火、笑里藏刀、李代桃僵、顺手牵羊。
第3套攻战计,打草惊蛇、借尸还魂、调虎离山、欲擒故纵、抛砖引玉、擒贼擒王。
第4套混战计,釜底抽薪、混水摸鱼、金蝉脱壳、关门捉贼、远交近攻、假道伐虢、
第5套并战计,偷梁换柱、指桑骂槐、假痴不颠、上楼抽梯、虚张声势、反客为主。
第6套败战计,美人计、空城计、反间计、苦肉计、连环计、走为上策。
</div>
</div>
<div>Footer</div>
</div>
<script>
const btn = document.querySelector('.btn')
const parentEl = document.querySelector('.parent')
btn.addEventListener('mouseenter', () => {
// 先设置为auto 然后去获取实际高度
parentEl.style.cssText += `height: auto`;
const { height } = parentEl.getBoundingClientRect();
// 先将高度设置为数字0 为了让过渡生效
parentEl.style.cssText += `height: 0`;
// 这行一定要加 需要让页面进行重绘
parentEl.offsetHeight;
parentEl.style.cssText += `height: ${height}px`;
});
btn.addEventListener('mouseleave', () => {
parentEl.style.cssText += `height: 0`;
})
</script>
</body>
</html>
效果如下: