首页 效果 正文
  • 本文约1548字,阅读需8分钟
  • 106
  • 0

三种方式实现元素高度在0和auto之间的过渡动画

摘要

CSS 过渡动画(transition)仅对可计算的数值型属性生效,而 height: auto 属于关键字属性,浏览器无法计算其具体数值变化,导致直接切换时动画失效,出现生硬的瞬间显示 / 隐藏效果。以下三种方案从不同角度解决这一问题。 方案一:Grid 网格布局实现(优点:兼容性最好) 实现原理 利用 CSS Grid 布局的 grid-template...

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() 实验性(少量浏览器支持) 极低 学习研究、未来场景预留

示例

评论
友情链接