实现动态高度过渡的3种方式

前言

今天在B站上看到了如何实现高度自动的过渡, 再加上我以前收集的内容,小记一下

关于 height 不可以设置过渡动画

我想只要是写过 css 对于这个属性就不陌生,它可以设置一个元素的高度, 那么为什么不可以设置过渡动画呢?

我有2点猜想:

  1. 因为动画需要 初始状态和结束状态,我们的初始状态是 0, 但是结束状态是不确定的
  2. 为了性能,因为改变高度需要导致页面重排,浏览器为了避免性能消耗

这只是我猜想,具体原因不清楚,以后知道了再补上

过渡

max-height

mdn-height 上有这么一句话, 这句话很重要

根据 mdn 对 height 的介绍,max-height 会覆盖 height 属性,我们可以设置一个较大的max-height 值来代替 height

html 复制代码
 <div class="maxHeightTransition" ref="maxHeightTransition">
        Lorem ipsum dolor sit amet consectetur adipisicing elit.
        Doloribus temporibus architecto enim,
        iure minima accusantium magni adipisci corrupti odio earum,
        necessitatibus aut delectus quibusdam porro distinctio
        sequi repellat at ullam?
 </div>

我们先给加上 max-hieght = 500px

css 复制代码
.maxHeightTransition {
  width: 100px;
  background-color: skyblue;
  transition: 0.5s;
  /*添加 500px*/
  max-hieght:500px
}

可以看到初始效果是这样的

我们加上 max-height = 0

css 复制代码
.maxHeightTransition {
 /*  
  * ....
  */
  overflow: hidden;
  max-height: 0px;
}

此时页面元素已经被隐藏,所以只需要切换 max-height 的值即可

js 复制代码
const maxHeightTransition = ref<HTMLDivElement | null>(null)
const isOpen = ref(false);

// 切换方法
const toggleHeight = () => {
  isOpen.value = !isOpen.value;
  maxHeightTransition.value.style.maxHeight = isOpen.value ? '0px' : '500px'
}

这种做法有一个很明显的缺点是,max-height 应该设置多少

如果过大,那么就会一段元素等待执行时间,看起来元素静止不动,然后开始突然收缩

如果过小,那么元素会被截断,会出现展开不完全的情况

只有当你知道这个元素大概高度的时候,可以考虑使用

requestAnimationFrame

window.requestAnimationFrame() 告诉浏览器------你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

重点: 重绘之前调用回调函数

我们可以利用这个特性

js 复制代码
// 要展开的元素
let el = content.value as HTMLElement

 el.style.height = 'auto';
 let h = el.offsetHeight;
 el.style.height = '0px';
 requestAnimationFrame(() => {
    el.style.height = h + 'px'
 })
  1. 我们先让元素的高度变为 auto,此时虽然高度变了,但是浏览器还没有刷新页面
  2. 然后获取他的 offsetHeight,此时就是结束时的高度
  3. 然后再高度重置为 0
  4. 最后在浏览器 重绘之前 再把高度还给他,此时浏览器就会从 0 开始变化到 结束高度

grid

这种方法也是视频中介绍的方法,即利用 grid-template-rows

html 复制代码
 <div class='box'>
      <div class="content">
        Lorem ipsum dolor sit amet consectetur adipisicing elit.
        Doloribus temporibus architecto enim,
        iure minima accusantium magni adipisci corrupti odio earum,
        necessitatibus aut delectus quibusdam porro distinctio
        sequi repellat at ullam?
      </div>
  </div>

我们在父元素上添加display:grid,并且设置 grid-template-rows: 0fr

css 复制代码
.box {
  width: 100px;
  background-color: skyblue;
  color: white;
  
  display: grid;
  grid-template-rows: 0fr;
  transition: 0.5s;
}

.content {
  min-height: 0;
  overflow: hidden;
}

由于设置了 0fr,元素不可见,同时在子元素上设置了 min-height: 0 防止文字填充高度

我们只需切换 grid-template-rows1fr 即可

html 复制代码
<div :class="['box', isOpen && 'open']">
    
</div>
js 复制代码
const isOpen = ref(false);
const toggleHeight = () => {
  isOpen.value = !isOpen.value;
 }
css 复制代码
.box:is(.open) {
  grid-template-rows: 1fr;
}

可以看到还是很流畅的

总结

今天介绍了 3 种关于动态高度的过渡

  1. 第一种 利用了 max-height 可以覆盖 height 属性,缺点是不容易控制max-height 的高度
  2. 第二种利用了 requestAnimationFrame 是会在下一帧执行回调,我们先计算得知结束高度,然后从0开始过渡到结束高度
  3. 第三种是利用了 grid-template-rows 的属性,通过设置 0fr 进行关闭,设置 1fr 进行展开
相关推荐
冴羽1 小时前
今日苹果 App Store 前端源码泄露,赶紧 fork 一份看看
前端·javascript·typescript
蒜香拿铁1 小时前
Angular【router路由】
前端·javascript·angular.js
brzhang1 小时前
读懂 MiniMax Agent 的设计逻辑,然后我复刻了一个MiniMax Agent
前端·后端·架构
西洼工作室1 小时前
高效管理搜索历史:Vue持久化实践
前端·javascript·vue.js
广州华水科技2 小时前
北斗形变监测传感器在水库安全中的应用及技术优势分析
前端
樱花开了几轉2 小时前
element ui下拉框踩坑
开发语言·javascript·ui
开发者如是说2 小时前
Compose 开发桌面程序的一些问题
前端·架构
故事不长丨2 小时前
【Java SpringBoot+Vue 实现视频文件上传与存储】
java·javascript·spring boot·vscode·后端·vue·intellij-idea
旺代2 小时前
Token 存储与安全防护
前端
洋不写bug3 小时前
html实现简历信息填写界面
前端·html