记录--不定高度展开收起动画 css/js 实现
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
不定高度展开收起动画
最近在做需求的时候,遇见了元素高度展开收起的动画需求,一开始是想到了使用 transition: all .3s;
来做动画效果,在固定高度的情况下,transition
动画很好使,满足了需求,但是如果要考虑之后可能还会有更改的情况下,如果每次都是用固定高度来做动画,会显得很繁琐,也很呆,就想到了使用 height: auto;
来做高度动画,但是,众所周知,高度设置成 auto
时是不会触发 transition
动画的
- .container {
- height: 0;
- background-color: #ccc;
- overflow: hidden;
- transition: all .3s;
- }
- .container:hover {
- height: 1000px;
- }
效果如图,不能满足动画的要求
在一番查找实验之后,目前发现了如下几种方法:
1. max-height
最大高度
transition
动画可以响应 max-height
- .container {
- max-height: 0;
- background-color: #ccc;
- overflow: hidden;
- transition: all .3s;
- }
- .container:hover {
- max-height: 1000px;
- }
但是使用 max-height
做动画有一个问题,如果设置的最大高度越大,但是实际高度确与最大高度相差甚远,那么整体的动画速度就会非常快,动画的时间只会是 实际高度 / 最大高度 * 动画时间,因为展开动画原本预期高度是设置的最大高度,所以整体时间是以最大高度完全展开所用时间来进行的,但是当到达实际高度的时候动画就停止了,所以最终动画时间会与期望时间相差甚远。
max-height
方法做动画也是一个好方法,如果能够确定大致高度的话,使用此方法是最简单也是最快的方法,但是如果不能确定大致高度或整体高度经常变化的话,可以考虑其他方法。
2. grid
动画
grid
网格布局,是一种较新的布局,号称是最强大的布局方案。grid
布局不是本文的介绍重点,并且较为复杂,如果感兴趣的话,可以参考相关文章,如:
grid
布局中可以使用 fr
单位,fr
单位是支持过度动画的(0fr=>1fr
),将 grid
布局下的子元素,初始设置为0fr
,在 :hover
状态下设置为 1fr
,就能够实现不定高度动画效果,但是如果子元素有内容,在设置 0fr
的时候,会被其内容撑开,所以要给子元素添加 min-height: 0;
- .container {
- display: grid;
- grid-template-rows: 0fr;
- overflow: hidden;
- transition: all .3s;
- }
- .container:hover {
- grid-template-rows: 1fr;
- }
- .container .child {
- min-height: 0;
- }
如果想要实现带有基础高度的展开收起动画,我们可以设置 min-height: 100px;
- .container .child {
- min-height: 100px;
- }
虽然此时实现了带有基础高度的动画效果,但是可以看到,如果我把 transition: all 3s;
的动画时间设置的较大,就可以看出来,虽然有基础高度,但是整个动画的效果还是要实现 0fr
到 1fr
的动画效果,基础高度部分不会有动画效果,这也算是一个小的缺点,如果动画时间较短并且基础高度也不大的话,可以这样使用,并不会有太大的影响效果。
但是 grid
布局有可能有兼容性的问题,grid-template-rows
动画的支持可能有兼容性问题
3. js 控制动画
写这篇文章的原因是因为在看项目代码的时候看见了 $(.xx).slideDown()
方法实现了元素的下滑动画,觉得很不错,想学习一下怎么实现的,实现效果如下:
但是在看元素的时候却只能看见下面的样子,发现不是 css 实现的,是使用 js 不断改变元素的高度来实现的:
我又去看了一下 ant-design
的 Menu
组件,通过观察元素,发现其也是不断改变高度来实现的(Ps: 我并没有去看源码,如果有误,多谢指正)。
实现
首先要思考整个实现的思路
展开的时候,元素从无到有,我们应该首先获取整个元素的实际高度使用 offsetHeight
来获取,获取到整体高度后就要计算每一次增加或者减少的高度,通过定时器不断增加或减少元素的高度,直到到了最大高度或 0 后停止
展开
- const element = document.getElementById('container');
- let expandTimer = null;
- let offsetHeight = 0;
- // 获取元素总高度
- element.style.display = 'block';
- let height = 0;
- // 先将 display 设置为 block,获取到的 offsetHeight 才是正确的高度,之后才能设置元素高度
- offsetHeight = element.offsetHeight;
- const stepHeight = offsetHeight / 30;
- element.style.height = height + 'px';
- expandTimer = setInterval(() => {
- height += stepHeight;
- if (height >= offsetHeight) {
- clearInterval(expandTimer);
- element.style = null;
- return;
- }
- element.style.height = height + 'px';
- }, 10);
收起
- let collapseTimer = null;
- offsetHeight = element.offsetHeight;
- let height = offsetHeight;
- const stepHeight = offsetHeight / 30;
- element.style.height = height + 'px';
- collapseTimer = setInterval(() => {
- height -= stepHeight;
- if (height <= 0) {
- clearInterval(collapseTimer);
- element.style = null;
- return;
- }
- element.style.height = height + 'px';
- }, 10);
现在能够正确展开收起,但是我们在展开收起的时候也会有相反的操作,比如鼠标进入元素展开离开收起,在展开的过程中鼠标离开了,我们应该立刻就将元素收起,而不是等动画结束后在进行下一个动画,所以要将展开收起操作合并操作才可以
- const element = document.getElementById('container');
- let expandTimer = null;
- let collapseTimer = null;
- // 我认为在一次展开后,直到收起完成之前,这个元素的实际高度都不应该发生变化,但是可以在下一次展开时发生变化,所以在展开时会进行赋值,在收起完成时会将此值清空
- let offsetHeight = 0;
- let stepHeight = 0;
- const handleClick = () => {
- // 如果当前 expandTimer 值存在,就标识当前是正在展开或已经展开,接下来要进行的是收起操作
- if (expandTimer) {
- clearInterval(expandTimer);
- expandTimer = null;
- // 收起时的初始高度是元素的当前实际高度,即使是元素在展开动画过程中,也要从当前元素高度进行收起动画
- let height = element.offsetHeight;
- collapseTimer = setInterval(() => {
- height -= stepHeight;
- if (height <= 0) {
- // 高度小于等于 0 代表动画完成,将数据进行重置
- clearInterval(collapseTimer);
- offsetHeight = 0;
- // 要将元素的高度置为 null,不然会影响下一次展开时获取正确的高度
- element.style.height = null;
- // display 设为 null,要将元素隐藏
- element.style.display = 'none';
- return;
- }
- element.style.height = height + 'px';
- }, 10);
- } else {
- clearInterval(collapseTimer);
- collapseTimer = null;
- // 获取元素总高度
- element.style.display = 'block';
- let height = 0;
- 如果当前没有 offsetHeight 就要重新获取
- if (!offsetHeight) {
- offsetHeight = element.offsetHeight;
- // 每一次给元素添加或减少的高度,除以 30 是自己设定的,跟下面定时器的每次间隔时间一起控制整个高度动画的时长,也可以给函数添加第二个时间参数,可以自由控制动画时间
- stepHeight = offsetHeight / 30;
- } else {
- // 如果有 offsetHeight 就代表正在进行收起动画,应该从收起动画的当前高度进行展开动画
- height = element.offsetHeight;
- }
- element.style.height = height + 'px';
- expandTimer = setInterval(() => {
- height += stepHeight;
- if (height >= offsetHeight) {
- // 当前高度如果已经到了元素的实际高度,就要清除定时器
- clearInterval(expandTimer);
- // 将 expandTimer 设为 1 是因为当前是以 expandTimer 判断是否正在或已经进行了展开动画,所以要在完成是设为 1,在收起动画的开始时会将值设为 null
- expandTimer = 1;
- element.style = null;
- return;
- }
- element.style.height = height + 'px';
- }, 10);
- }
- };
最终实现效果
4. 总结
上面的三种方式实现效果都是各有千秋 - max-height
方法实现是最简单,也是效率最高的方式,但是也有动画时间不定的缺陷 - grid
方式实现比 max-height
稍微复杂一些,但是整体效果要比 max-height
更好,但是目前浏览器的支持方面可能有所不足,如果有低版本的兼容性要求的话,还是不能使用 - js
方式整体最复杂,但是却没有上面两种方式的缺陷与问题,使用范围也更广泛,但是是 js
的实现方式,性能肯定是不如 css
,虽然不如,但是由于整体操作也较为简单,所以也不会有什么性能问题
几种方法的取舍全看个人需求了。
如果有鼠标进入展开,离开收起的操作,可以配合使用 onmouseover
onmouseout
事件来监听鼠标的进入离开。
其他还有像是 transform: scale(0);
的实现也是可以,但是整体动画效果就是一个缩小的效果,而且元素还会有占位问题,如果没什么要求也是可以使用的。
本文转载于:
https://juejin.cn/post/7249536369474486329
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
记录--不定高度展开收起动画 css/js 实现的更多相关文章
- 右上角鼠标滑过展开收缩动画效果js代码的演示页面
http://files.cnblogs.com/files/tanlingdangan/top_right.rar.gz 右上角鼠标滑过展开收缩动画效果js代码的演示页面http://www.51x ...
- vue.js 实现点击展开收起动画
最近公司项目加了个页面,其中要求是这样的,点击对应列表,展开和收起, 其实就是显示和隐藏内容部分:说来惭愧,我花了半天时间才搞出来(自黑一下~), ,,接下来分享给大家,先上效果图: .vue页面: ...
- css3实现手机菜单展开收起动画
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- [TimLinux] CSS 纯CSS实现动画展开/收起功能
内容转自CSS世界,理解之后进行了简化,简化后代码: <!DOCTYPE html> <html> <head> <meta charset=utf-8 /& ...
- max-height实现任意高度元素的展开收缩动画
http://dobinspark.com.cn/ 前言: 在说到实现元素的展开收缩,通常的想法是通过控制display的元素属性和none之间的切换,虽然说功能可以实现,但是这种展开是没有任何动画的 ...
- 如何为不定高度(height:auto)的元素添加CSS3 transition-property:height 动画
但一个元素不设置height时,它的默认值是 auto,浏览器会计算出实际的高度. 但如果想给一个 height:auto 的块级元素的高度添加 CSS3 动画时,该怎么办呢? 从 MDN 的可以查到 ...
- 前端案例分享(一):CSS+JS实现流星雨动画
目录 引言 1.效果图 2.源码 3.案例解析 4.小问题 5.结语 引言 平常会做一些有意思的小案例练手,通常都会发到codepen上,但是codepen不能写分析. 所 ...
- CSS+JS实现流星雨动画
引言 平常会做一些有意思的小案例练手,通常都会发到codepen上,但是codepen不能写分析. 所以就在博客上开个案例分享系列,对demo做个剖析.目的以分享为主,然后也希望各路大神 ...
- css实现侧边展开收起
前言:因为突然想研究研究侧边栏滑动展开收起怎么做的,就去baidu了一下transition. 详情 内容1 内容1 内容1 内容1 内容1 右侧有实现demo.就是那个绿色的详情 先来看一下我的代码 ...
- Web高性能动画及渲染原理(1)CSS动画和JS动画
目录 一. CSS动画 和 JS动画 1.1 CSS动画 1.2 JS动画 1.3 小结 二. 使用Velocity.js实现动画 示例代码托管在:http://www.github.com/dash ...
随机推荐
- Pandas日期时间格式化
当进行数据分析时,我们会遇到很多带有日期.时间格式的数据集,在处理这些数据集时,可能会遇到日期格式不统一的问题,此时就需要对日期时间做统一的格式化处理.比如"Wednesday, June ...
- Java并发编程-CompletableFuture(下)
大家好,我是小高先生,书接上文,我们继续来学习CompletableFuture.上文我们讲了基础装Future是如何升级为神装CompletableFuture以及如何购买CompletableFu ...
- 有了这份Java面试中的葵花宝典,让你面试起飞!!!
HashMap面试题 HashMap与HashTable的区别 1.HashMap线程不安全 HashTable 线程是安全的采用synchronized 2.HashMap允许存放key 为null ...
- SSH不对称密钥自动登入服务器
SSH不对称密钥自动登入服务器 1.先在自己的电脑上创建密钥对 ssh-keygen -t rsa Windows下生成SSH密钥 $ ssh-keygen -t rsa -C "youre ...
- 【Azure 服务总线】使用Azure Service Bus 时,出现证书错误: 所使用的证书具有无法验证的信任链
问题描述 在Azure中连接 Service Bus 服务发送消息时发生证书错误,抛出证书异常消息: 或 The X.509 certificate CN=servicebus.chinaclouda ...
- 文心一言 VS 讯飞星火 VS chatgpt (205)-- 算法导论15.4 1题
一.求〈1,0,0,1,0,1,0,1〉和〈0,1,0,1,1,0,1,1,0〉的一个LCS.需要写代码的时候,请用go语言. 文心一言,代码正常运行: 在Go语言中,求两个序列的最长公共子序列(Lo ...
- BIGO 的数据管理与应用实践
本文首发于 Nebula Graph Community 公众号 本文整理自 BIGO 在 nMeetp 上的主题分享,主要介绍 BIGO 过去一年在数据管理建设方面的理解和探索.而 BIGO 数据管 ...
- [C++逆向] 7 变量在内存中的位置和访问方式
目录 全局变量和局部变量的区别 局部静态变量 有意思的 堆变量 变量类型 作用域 可访问 全局变量 进程作用域 整个进程可访问 静态变量 文件作用域 当前代码文件可访问 局部变量 函数作用域 函数内可 ...
- Redis项目常见解决方案
## 1. 缓存预热 在项目启动,或者服务器重启后, 因为请求量较大, 此时对关系型数据库的访问量就有可能超标,导致服务卡顿,宕机, 所以在启动前应该对缓存进行预热: 前置准备工作: 日常例行统计数据 ...
- Java 抽象类 练习
1 package com.bytezreo.template; 2 3 import java.util.Calendar; 4 import java.util.Scanner; 5 6 /** ...