Skip to content
On this page

实现高度过渡

在工作中有时候会遇到点击实现Collapse折叠效果,而折叠的元素高度可能不固定的,使用height: 0height: 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: 0max-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

css
.parent {
    transform: scaleY(0);
    transform-origin: top center;
    transition: .5s linear;
}
.btn:hover + .parent {
    transform: scaleY(1);
}

这种方法会使文字有拉伸效果,而且不做其他处理的话,未展开时,还占据了布局空间

效果如下:

grid

  • 点击grid查看效果

可以通过grid布局来时间,通过设置元素的grid-template-rows属性从0fr1fr切换实现

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来实现

该方法的原理如下:

  • 需要展开时先设置元素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>

效果如下: