CSS实现展开动画

展开收起效果是比较常见的一种交互方式,通常的做法是控制display属性值在none和其它值之间切换,虽说功能可以实现,但是效果略显生硬,所以会有这样的需求——希望元素展开收起能具有平滑的效果。

实现

max-height

首先想到的是通过height0auto之间切换,但是结果可能并不会是我们所预期的那样,原因是我们将要展开的元素内容是动态的,即高度值不确定,因此height使用的值是默认的auto,从0pxauto是无法计算的,因此无法形成过渡或动画效果。

据此我们可以使用max-height,将max-height0过渡到一个能够大于完全显示内部元素的值,展开后的max-height值,只需要设定为保证比展开内容高度大的值即可,在max-height值比height值大的情况下,元素仍会默认采用自身的高度值即auto,如此一来一个高度不定的元素展开收起动画效果就实现了。

请注意这种方式实现还是有限制的,使用CSS进行过渡动画的时候依旧是通过计算0到设定的max-height高度值进行计算的,在实际应用中如果max-height值太大,在元素收起的时候将会产生延迟的效果,这是因为在收起时,max-height从设定的特别大的值,到元素自身高度值的变化过程将占用较多时间,此时画面表现则会产生延迟的效果。因此建议将max-height值设置为足够安全的最小值,这样在收起时即使有略微延迟,也会因为时间很短,难以被用户感知,将不会影响体验。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>展开动画</title>
  5. <style type="text/css">
  6. .page{
  7. width: 200px;
  8. padding: 10px 20px;
  9. border: 1px solid #eee;
  10. }
  11. .container {
  12. overflow: hidden;
  13. }
  14. .container > .options{
  15. transition: all .5s;
  16. max-height: 0;
  17. }
  18. .container > .unfold{
  19. max-height: 150px;
  20. }
  21. .container > .btn{
  22. color: #4C98F7;
  23. cursor: pointer;
  24. text-decoration: underline;
  25. }
  26. </style>
  27. </head>
  28. <body>
  29. <div class="page">
  30. <div class="container">
  31. <div class="btn" onclick="operate(this)" unfold="1">展开</div>
  32. <div class="options">
  33. <div class="option">选项1</div>
  34. <div class="option">选项2</div>
  35. <div class="option">选项3</div>
  36. <div class="option">选项4</div>
  37. <div class="option">选项5</div>
  38. <div class="option">选项6</div>
  39. <div class="option">选项7</div>
  40. </div>
  41. </div>
  42. </div>
  43. </body>
  44. <script type="text/javascript">
  45. function operate(btn){
  46. const optionsNode = document.querySelector(".container > .options");
  47. const unfold = btn.getAttribute("unfold");
  48. if(unfold && unfold==="1"){
  49. btn.innerText = "收缩";
  50. optionsNode.classList.add("unfold");
  51. }else{
  52. btn.innerText = "展开";
  53. optionsNode.classList.remove("unfold");
  54. }
  55. btn.setAttribute("unfold", unfold === "0" ? "1" : "0");
  56. }
  57. </script>
  58. </html>

height

使用max-height必定有一定的局限性,那么不如我们在DOM加载完成后就取得元素的实际高度并保存,之后直接利用这个真实高度与0进行动画过渡即可,因为浏览器的渲染顺序,在解析JavaScript时会阻塞DOM的渲染,所以在获取元素实际高度再设置高度为0的过程中一般不会出现闪烁的情况,如果实在担心因为获取高度之后再将高度设置为0可能会有一个闪烁的过程,那么我们可以取得元素父节点后调用cloneNode(true)方法或者innerHTML方法取得字符串再innerHTML到一个新创建的节点,目的就是将其拷贝,之后将其使用绝对定位等放置到屏幕外即将其设置到屏幕能够显示的外部区域,注意此时要设置bodyoverflow: hidden;,之后利用getComputedStyle取得实际高度,然后再将其移出DOM结构,此时有了实际高度就可以进行动画过渡了,下面简单的实现一下在DOM加载时便取得实际高度进行动画实现。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>展开动画</title>
  5. <style type="text/css">
  6. .page{
  7. width: 200px;
  8. padding: 10px 20px;
  9. border: 1px solid #eee;
  10. }
  11. .container {
  12. overflow: hidden;
  13. }
  14. .container > .options{
  15. transition: all .5s;
  16. }
  17. .container > .btn{
  18. color: #4C98F7;
  19. cursor: pointer;
  20. text-decoration: underline;
  21. }
  22. </style>
  23. </head>
  24. <body>
  25. <div class="page">
  26. <div class="container">
  27. <div class="btn" onclick="operate(this)" unfold="1">展开</div>
  28. <div class="options">
  29. <div class="option">选项1</div>
  30. <div class="option">选项2</div>
  31. <div class="option">选项3</div>
  32. <div class="option">选项4</div>
  33. <div class="option">选项5</div>
  34. <div class="option">选项6</div>
  35. <div class="option">选项7</div>
  36. </div>
  37. </div>
  38. </div>
  39. </body>
  40. <script type="text/javascript">
  41. (function init(win, doc){
  42. const optionsNode = document.querySelector(".container > .options");
  43. optionsNode.setAttribute("real-height", win.getComputedStyle(optionsNode).height);
  44. optionsNode.style.height = "0px";
  45. })(window, document);
  46. function operate(btn){
  47. const optionsNode = document.querySelector(".container > .options");
  48. const unfold = btn.getAttribute("unfold");
  49. const realHeight = optionsNode.getAttribute("real-height");
  50. if(unfold && unfold==="1"){
  51. btn.innerText = "收缩";
  52. optionsNode.style.height = realHeight;
  53. }else{
  54. btn.innerText = "展开";
  55. optionsNode.style.height = "0px";
  56. }
  57. btn.setAttribute("unfold", unfold === "0" ? "1" : "0");
  58. }
  59. </script>
  60. </html>

translateY

还有一种常用实现动画的方式,即首先将外层元素没有动画过渡的形式直接展开,再将选项加入动画缓慢下落,通常利用transform: translateY();去实现这个缓慢下降的动画,在微信的WEUI小程序组件库的首页就是采用这种实现方式。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>展开动画</title>
  5. <style type="text/css">
  6. .page{
  7. width: 200px;
  8. padding: 10px 20px;
  9. border: 1px solid #eee;
  10. }
  11. .container, .options-container {
  12. overflow: hidden;
  13. }
  14. .options-container{
  15. height: 0;
  16. }
  17. .container .options{
  18. transition: all .5s;
  19. transform: translateY(-100%);
  20. }
  21. .container .unfold{
  22. transform: translateY(0);
  23. }
  24. .container > .btn{
  25. color: #4C98F7;
  26. cursor: pointer;
  27. text-decoration: underline;
  28. }
  29. </style>
  30. </head>
  31. <body>
  32. <div class="page">
  33. <div class="container">
  34. <div class="btn" onclick="operate(this)" unfold="1">展开</div>
  35. <div class="options-container">
  36. <div class="options">
  37. <div class="option">选项1</div>
  38. <div class="option">选项2</div>
  39. <div class="option">选项3</div>
  40. <div class="option">选项4</div>
  41. <div class="option">选项5</div>
  42. <div class="option">选项6</div>
  43. <div class="option">选项7</div>
  44. </div>
  45. </div>
  46. </div>
  47. </div>
  48. </body>
  49. <script type="text/javascript">
  50. function operate(btn){
  51. const optionsNode = document.querySelector(".container .options");
  52. const optionsContainer = document.querySelector(".options-container");
  53. const unfold = btn.getAttribute("unfold");
  54. if(unfold && unfold==="1"){
  55. btn.innerText = "收缩";
  56. optionsNode.classList.add("unfold");
  57. optionsContainer.style.height = "auto";
  58. }else{
  59. btn.innerText = "展开";
  60. optionsNode.classList.remove("unfold");
  61. optionsContainer.style.height = "0px";
  62. }
  63. btn.setAttribute("unfold", unfold === "0" ? "1" : "0");
  64. }
  65. </script>
  66. </html>

每日一题

  1. https://github.com/WindrunnerMax/EveryDay

参考

  1. http://www.111com.net/wy/192615.htm
  2. https://zhuanlan.zhihu.com/p/52582555
  3. https://cloud.tencent.com/developer/article/1499033

CSS实现展开动画的更多相关文章

  1. jQuery鼠标悬停3d菜单展开动画

    效果体验:http://hovertree.com/texiao/jquery/93/ 竖直的主菜单贴着页面左侧,当光标移入菜单项时,以3D动画的方式弹出对应的二级菜单.采用jQuery和CSS3实现 ...

  2. 为网格布局图片打造的超炫 CSS 加载动画

    今天,我想与大家分享一些专门为网格布局的图像制作的很酷的 CSS 加载动画效果.您可以把这些效果用在你的作品集,博客或任何你想要的网页中.设置很简单.我们使用了下面这些工具库来实现这个效果: Norm ...

  3. 一个纯CSS DIV天气动画图标【转扒的】

    <p> </p> <style><!-- /* SUNNY */ .sunny { -webkit-animation: sunny 15s linear i ...

  4. WPF(C#) 矩阵拖动、矩阵动画、边缘展开动画处理。

    最近在研发新的项目,遇到了一个桌面模式下的难点--展开动画.之前动画这方面没做过,也许很多人开始做的时候也会遇到相关问题,因此我把几个重点及实际效果图总结展示出来: 我的开发环境是在VS2017下进行 ...

  5. CSS图片翻转动画技术详解

    因为不断有人问我,现在我补充一下:IE是支持这种技术的!尽管会很麻烦.需要做的是旋转front和back元素,而不是旋转整个容器元素.如果你使用的是最新版的IE,可以忽略这一节.IE10+是支持的,I ...

  6. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

  7. 简单的CSS圆形缩放动画

    简单的CSS圆形缩放动画 话不多说鼠标移动上去,看效果吧,效果预览 代码如下: <!DOCTYPE html> <html> <head> <title> ...

  8. 网页DIV+CSS布局和动画美化全程实例 (陈益材) 随书光盘

    网站的建站技术近几年得到迅速的发展,网页的布局与特效动画技术层出不穷,网站建设已经从简单的技术支持时代衍变到现在的视觉美化时代.但如何使设计的网页高人一筹,达到让人过目不忘的境界,如何追求以最简单的特 ...

  9. animate.css引入实现动画效果

    最近在网上看到很多代码都通过引入animate.css来实现动画效果,后来我便使用这种方法来尝试着写了个小案例,结果真的很好用,比我们通常情况下使用css或js实现动画效果好得多,便在此做个总结. 第 ...

  10. How Javascript works (Javascript工作原理) (十三) CSS 和 JS 动画底层原理及如何优化其性能

    个人总结:读完这篇文章需要20分钟. 这是 JavaScript 工作原理的第十三章. 概述 正如你所知,动画在创建令人叹服的网络应用中扮演着一个关键角色.由于用户越来越注重用户体验,商户开始意识到完 ...

随机推荐

  1. 【TouchGFX】代码结构

    生成代码与用户代码 代码结构图示如下 据上图显示代码结构分为三层 引擎 这是TouchGFX提供的标准类,作为生成类的基类 生成 这是touchgfx designer生成的类,作为用户类的基类,这部 ...

  2. 用CI/CD工具Vela部署Elasticsearch + C# 如何使用

    Vela 除了可以帮我们编译.部署程序,利用它的docker部署功能,也能用来部署其他线上的docker镜像,例如部署RabbitMQ.PostgreSql.Elasticsearch等等,便于集中管 ...

  3. [转帖]KVM调整磁盘大小

    https://www.jianshu.com/p/5ca598424eb9 一台win10的虚拟机磁盘空间不足了,需要调整磁盘的大小.上网搜索KVM调整磁盘大小,结果得出的博客都说只有raw格式的能 ...

  4. [转帖]br备份时排除某个库

    https://tidb.net/blog/2a88149e?utm_source=tidb-community&utm_medium=referral&utm_campaign=re ...

  5. [转帖]MySQL ALTER TABLE: ALTER vs CHANGE vs MODIFY COLUMN

    https://www.cnblogs.com/pachongshangdexuebi/p/5029152.html ALTER COLUMN 语法: ALTER [COLUMN] col_name ...

  6. Rsync原理的学习与总结

    Rsync原理的简单学习 前言 工作这么多年, 感觉对自己帮助最大的是rsync. 用了很多rsync的脚本, 甚至因为这个脚本授权了两个专利. 但是昨天晚上在跟高手聊天时发现 自己对rsync 其实 ...

  7. [转帖]Linux磁盘I/O(二):使用vm.dirty_ratio和vm.dirty_background_ratio优化磁盘性能

    文件缓存是一项重要的性能改进,在大多数情况下,读缓存在绝大多数情况下是有益无害的(程序可以直接从RAM中读取数据).写缓存比较复杂,Linux内核将磁盘写入缓存,过段时间再异步将它们刷新到磁盘.这对加 ...

  8. [转帖]关于redis,你需要了解的几点!

    github:https://github.com/windwant 博客园 首页 新随笔 联系 订阅 管理 随笔 - 227  文章 - 4  评论 - 36  阅读 - 73万   一.关于 re ...

  9. [转帖]018 磁盘 IO 性能监控 / 压测工具 (sar、iotop、fio、iostat)

    https://my.oschina.net/u/3113381/blog/5465063   1 sar 命令查看当前磁盘 IO 读写 sar(System Activity Reporter 系统 ...

  10. 全球 IPv4 耗尽,下个月开始收费!

    哈喽大家好,我是咸鱼 IPv4(Internet Protocol version 4)是互联网上使用最广泛的网络层协议之一,于1981年在 RFC 791 中发布,它定义了 32 位的IP地址结构和 ...