CSS实现auto高度的过渡动画

原文链接:CSS实现auto高度的过渡动画

问题描述

下面是一个常见的效果,当鼠标悬浮时展开显示内容,离开时自动收回。

html 复制代码
<div id="wrapper">
    <h4>hover me!</h4>
    <div id="content">
        <p>Hello, World!</p>
        <p>Hello, World!</p>
        <p>Hello, World!</p>
        <p>Hello, World!</p>
    </div>
</div>
css 复制代码
#wrapper {
    width: 240px;
    padding: 16px 24px;
    border-radius: 12px;
}
#content p {
    line-height: 32px;
}
#content {
    height: 0;
    overflow: hidden;
    /*不起作用*/
    transition: height 500ms;
}
#wrapper:hover #content {
    height: auto;
}

由于通常不知道content中具体内容所占的高度,因此常用height: auto;设置高度。上面的示例可以良好的实现要求,问题出现在当我们需要为这个高度的变化添加过渡动画时,会发现transition: height 200ms;不起作用,这是因为auto并不是一个具体的高度数值。

使用 max-height 解决

一个常见方案是使用max-height控制。这样确实可以实现过渡动画效果,但并不是一个"完美"的动画:

当过高的估计了content容器的最大可能高度时,鼠标移入时的动画会的变快,而移出时动画会有延迟。这是因为有一部分时间花在了max-height数值在content容器的真实高度和设定值之间的过渡上,而这部分过渡时间不会影响页面元素的样式。

css 复制代码
#wrapper {
    width: 240px;
    padding: 16px 24px;
    border-radius: 12px;
}
#content p {
    line-height: 32px;
}
#content {
    /*起始高度*/
    max-height: 0;
    overflow: hidden;
    transition: max-height 500ms;
}
#wrapper:hover #content {
    /*确保大于content最大可能高度*/
    max-height: 600px;
}

更好的方案:使用 grid

一个更完美的解决方案是使用网格布局:

注意在html结构中,要为content再添加一层子元素div,display: grid;grid-template-rows属性仍然设置给content,但此时overflow: hidden;要设置给content的子元素。

html 复制代码
<div id="wrapper">
    <h4>hover me!</h4>
    <div id="content">
        <div>
            <p>Hello, World!</p>
            <p>Hello, World!</p>
            <p>Hello, World!</p>
            <p>Hello, World!</p>
        </div>
    </div>
</div>
css 复制代码
#wrapper {
    width: 240px;
    padding: 16px 24px;
    border-radius: 12px;
}
#content p {
    line-height: 32px;
}
#content {
    display: grid;
    grid-template-rows: 0fr;
    transition:
        grid-template-rows 500ms;
}
#content > div {
    /*使子元素动画与父元素保持一致*/
    grid-row: 1 / span 2;
    /*overflow也设置给子元素*/
    overflow: hidden;
}
#wrapper:hover #content {
    grid-template-rows: 1fr;
}

讨论

grid-row: 1 / span 2;这行代码看起来有些费解,因为毕竟只有一行子元素。它的作用是使子元素动画与父元素保持一致。

我们把动画放慢,并且给content带上灰色背景,给content > div带上红色背景,观察一下使用和不使用这个属性的区别:

注:这个问题是否发生似乎与浏览器的行为有关:在我测试时,使用Google Chrome和Microsoft Edge时二者表现是不同的,但在Firefox中是相同的,即使不写grid-row: 1 / span 2;也不会引起这个问题。

相关推荐
GISer_Jing4 分钟前
前端面试常考题目详解
前端·javascript
Boilermaker19921 小时前
【Java EE】SpringIoC
前端·数据库·spring
中微子1 小时前
JavaScript 防抖与节流:从原理到实践的完整指南
前端·javascript
天天向上10241 小时前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y2 小时前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁2 小时前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry2 小时前
Fetch 笔记
前端·javascript
拾光拾趣录2 小时前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟2 小时前
vue3,你看setup设计详解,也是个人才
前端
Lefan2 小时前
一文了解什么是Dart
前端·flutter·dart