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;也不会引起这个问题。

相关推荐
全栈技术负责人6 小时前
AI 效能工具建设:Agent 可观测性技能技术方案与实践
前端·ai·ai编程
梦想平凡6 小时前
百游棋牌源代码开发搭建教程(一):全端工程结构、开发环境配置与首次启动验证
前端·javascript·源代码管理
妙码生花6 小时前
两个月 59 篇 AI 开发日志 + Golang 商业级实战项目收工后,得来的 AI 使用心法-上
前端·后端·gin
vx-Biye_Design6 小时前
springboot中国传统节日宣传平台49078-计算机课程设计、毕业设计
java·前端·vue.js·spring boot·后端·课程设计·idea
妙码生花6 小时前
两个月 59 篇 AI 开发日志 + Golang 商业级实战项目收工后,得来的 AI 使用心法-下
前端·后端·go
计算机魔术师7 小时前
Beren Millidge、John Schulman、Charlie O'Neill 对谈递归自我改进离我们还有多远
前端
MetaLite7 小时前
Java 时间处理的两个坑:单位误判,半秒算成一秒
java·开发语言·前端
hiahiahia1237 小时前
SSE 到底是什么?
前端·人工智能
Bigger7 小时前
我把苹果发布会里的折叠屏,真的用网页做出来了
前端·ai编程·交互设计
钱栈up8 小时前
qoder CLI 1.0.45 本地小说生成工作流搭建:Feature Gate 配置与长文本断连排查从死锁到全流程跑通:Python德州扑克项目的优化
java·前端·数据库