三种方式实现元素高度在0和auto之间的过渡动画
CSS 过渡动画(transition)仅对可计算的数值型属性生效,而 height: auto 属于关键字属性,浏览器无法计算其具体数值变化,导致直接切换时动画失效,出现生硬的瞬间显示 / 隐藏效果。以下三种方案从不同角度解决这一问题。
方案一:Grid 网格布局实现(优点:兼容性最好)
实现原理
利用 CSS Grid 布局的 grid-template-rows 属性,通过 0fr(收起状态,高度为 0)和 1fr(展开状态,高度自适应内容)的切换,配合子元素 overflow: hidden 实现动画。fr 单位是可计算的网格轨道单位,因此能触发平滑过渡。
代码实现
<template>
<div class="demo-item demo1">
<h3>1. 使用 Grid 布局实现</h3>
<hr />
<el-button type="primary" @click="isExpand1 = !isExpand1">
{{ isExpand1 ? "收起" : "展开" }}
</el-button>
<hr />
<!-- 容器:通过 grid-template-rows 控制高度 -->
<div class="container" :style="{ gridTemplateRows: isExpand1 ? '1fr' : '0fr' }">
<!-- 内容容器:必须设置 overflow: hidden -->
<div style="overflow: hidden;">{{ Mock.mock("@csentence(200, 400)") }}</div>
</div>
</div>
</template>
<script setup>
import Mock from 'mockjs';
import { ref } from "vue";
const isExpand1 = ref(false); // 控制展开收起状态
</script>
<style lang="scss" scoped>
.demo1 {
.container {
display: grid; /* 启用 Grid 布局 */
grid-template-rows: 0fr; /* 默认收起 */
margin-left: 10px;
transition: all 0.5s; /* 平滑过渡 */
}
}
</style>
方案二:interpolate-size 属性(现代浏览器原生方案)
实现原理
interpolate-size 是 CSS 原生属性,用于控制浏览器如何插值计算关键字尺寸(如 auto、min-content 等)。设置为 allow-keywords 后,浏览器会自动计算 height: 0 到 height: auto 的中间过渡值,从而触发平滑动画。。
代码实现
<template>
<div class="demo-item demo2">
<h3>2. 使用 interpolate-size: allow-keywords</h3>
<hr />
<el-button type="primary" @click="isExpand2 = !isExpand2">
{{ isExpand2 ? "收起" : "展开" }}
</el-button>
<hr />
<!-- 直接切换 height: 0 和 auto -->
<div class="container" :style="{ height: isExpand2 ? 'auto' : '0' }">
{{ Mock.mock("@csentence(200, 400)") }}
</div>
</div>
</template>
<script setup>
import Mock from 'mockjs';
import { ref } from "vue";
const isExpand2 = ref(false);
</script>
<style lang="scss" scoped>
.demo2 {
.container {
margin-left: 10px;
overflow: hidden; /* 关键:隐藏溢出内容 */
interpolate-size: allow-keywords; /* 允许关键字插值计算 */
transition: all 0.5s; /* 平滑过渡 */
}
}
</style>
方案三:calc-size () 函数(实验性方案)
实现原理
calc-size() 是 CSS 实验性函数,用于计算元素的自适应尺寸,语法为 calc-size(auto, size),表示 " 计算元素的自动高度,并将其作为 size 变量供过渡使用 "。配合 overflow: hidden 和 height 切换,实现平滑动画。
代码实现
<template>
<div class="demo-item demo3">
<h3>3. 使用 calc-size(auto, size) 函数</h3>
<hr />
<el-button type="primary" @click="isExpand3 = !isExpand3">
{{ isExpand3 ? "收起" : "展开" }}
</el-button>
<hr />
<!-- 展开时使用 calc-size 计算自动高度,收起时为 0 -->
<div class="container" :style="{ height: isExpand3 ? 'calc-size(auto, size)' : '0' }">
{{ Mock.mock("@csentence(200, 400)") }}
</div>
</div>
</template>
<script setup>
import Mock from 'mockjs';
import { ref } from "vue";
const isExpand3 = ref(false);
</script>
<style lang="scss" scoped>
.demo3 {
.container {
margin-left: 10px;
overflow: hidden; /* 关键:隐藏溢出内容 */
transition: all 0.5s; /* 平滑过渡 */
}
}
</style>
三种方案对比
| 方案 | 兼容性 | 代码复杂度 | 适用场景 |
|---|---|---|---|
| Grid 布局 | 良好(IE 除外) | 低 | 生产环境首选,需兼容多浏览器 |
| interpolate-size | 现代浏览器(Chrome 117+) | 极低 | 内部系统、现代浏览器专属项目 |
| calc-size() | 实验性(少量浏览器支持) | 极低 | 学习研究、未来场景预留 |