多种方式实现 元素高度丝滑的从0-1显示出来

选择合适的方式,给用户更好的体验,多种方式实现 元素高度丝滑的从0-1显示出来。

能用 CSS 实现的动画,就不要采用 JS 去实现。

1、浏览器可以对CSS动画进行优化,其优化原理类似于requestAnimationFrame,会把每一帧的DOM操作都集中起来,在一次重绘和回流中去完成。一般来说频率为每秒60帧。

2、隐藏和不可见的dom不会进行重绘或回流,这样就会更少的使用CPU,GPU和内存使用量。

3、可以强制使用硬件加速;对于帧速不好的浏览器,css3可以做到自动降级,js则需要添加额外的代码。

对requestAnimationFrame有兴趣的可以看看作者的这个文。
提升用户体验之requestAnimationFrame实现前端动画_requestanimation 浏览器重绘-CSDN博客

1) 通过transition + height方式

transition只针对数值变化有效,所以 height:auto 不触发过渡动画,height:200px可触发动画 但该数值固定,无法满足不固定长度的情况。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .elA {
      width: 150px;
      height: 50px;
      background-color: #eee;
    }

    .elB {
      width: 300px;
      background-color: #5b734a;
      color: #ddd;
      height: 0;
      overflow: hidden;
      transition: 1s;
      position: absolute;
    }

    /* transition只针对数值变化有效,所以 height:auto 不触发过渡动画,
    height:200px可触发动画 但该数值固定,无法满足不固定长度的情况。*/
    .elA:hover+.elB {
      height: 200px;
    }
  </style>
</head>

<body>
  <div class="elA">元素A
  </div>
  <div class="elB">
    元素B
    <div class="inner">
      Lorem ipsum dolor sit amet consectetur adipisicing elit.<br>
      Architecto officiis repudiandae natus dolores quos porro
      eveniet eum temporibus aspernatur <br>commodi sapiente ab accusantium
      dolorem nisi id nemo, obcaecati velit non.
    </div>
  </div>
</body>

</html>
2) 通过transition + max-height方式

因无法确认显示内容最大高度,会导致设置高度过大,回缩时有延迟

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .elA {
      width: 150px;
      height: 50px;
      background-color: #eee;
    }

    .elB {
      width: 300px;
      background-color: #5b734a;
      color: #ddd;
      max-height: 0;
      overflow: hidden;
      transition: 1s;
      position: absolute;
    }

    /* 因无法确认显示内容最大高度,会导致设置高度过大,回缩时有延迟 */
    .elA:hover+.elB {
      max-height: 1000px;
    }
  </style>
</head>

<body>
  <div class="elA">元素A
  </div>
  <div class="elB">
    元素B
    <div class="inner">
      Lorem ipsum dolor sit amet consectetur adipisicing elit.<br>
      Architecto officiis repudiandae natus dolores quos porro
      eveniet eum temporibus aspernatur <br>commodi sapiente ab accusantium
      dolorem nisi id nemo, obcaecati velit non.
    </div>
  </div>
</body>

</html>
3) 通过transition + tranform:scale(0/1)

使用这种方式时,展示收回会出现一个压缩的过程

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .elA {
      width: 150px;
      height: 50px;
      background-color: #eee;
    }

    .elB {
      width: 300px;
      background-color: #5b734a;
      color: #ddd;
      transform-origin: center top;
      transform: scaleY(0);
      overflow: hidden;
      transition: 1s;
      position: absolute;
    }

    /* scale回缩时,会有展示出一个压缩的过程 */
    .elA:hover+.elB {
      transform: scaleY(1);
    }
  </style>
</head>

<body>
  <div class="elA">元素A
  </div>
  <div class="elB">
    元素B
    <div class="inner">
      Lorem ipsum dolor sit amet consectetur adipisicing elit.<br>
      Architecto officiis repudiandae natus dolores quos porro
      eveniet eum temporibus aspernatur <br>commodi sapiente ab accusantium
      dolorem nisi id nemo, obcaecati velit non.
    </div>
  </div>

</body>

</html>
4) 通过JS方式实现元素高度 丝滑展示

强制回流

1、(当DOM元素的大小、位置或可见性发生变化时,浏览器需要重新计算页面布局,这个过程就是回流。

        这里通过计算的方式,实现回流。elB.getBoundingClientRect()

2、requestAnimationFrame的回调函数中进行DOM操作,如改变元素的样式、尺寸或位置,这些操作会排队等待浏览器的下一个重绘周期,触发回流。

        requestAnimationFrame(cb)的方式触发回流。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .elA {
      width: 150px;
      height: 50px;
      background-color: #eee;
    }

    .elB {
      width: 300px;
      background-color: #5b734a;
      color: #ddd;
      overflow: hidden;
      transition: 1s;
      position: absolute;
      height: 0;
    }
  </style>
</head>

<body>
  <div class="elA">元素A
  </div>
  <div class="elB">
    元素B
    <div class="inner">
      Lorem ipsum dolor sit amet consectetur adipisicing elit.<br>
      Architecto officiis repudiandae natus dolores quos porro
      eveniet eum temporibus aspernatur <br>commodi sapiente ab accusantium
      dolorem nisi id nemo, obcaecati velit non.
    </div>
  </div>
  <script>
    let elA = document.querySelector('.elA')
    let elB = document.querySelector('.elB')
    elA.onmouseenter = () => {
      // 先获取元素的自适应原始高度
      elB.style.height = 'auto'
      let h = elB.getBoundingClientRect().height
      // 回到最初的高度
      elB.style.height = 0
      // 代码到这里,页面会直接保持高度为0的状态,不会有动画。

      // 强制回流
      // 方式一、计算,(当DOM元素的大小、位置或可见性发生变化时,浏览器需要重新计算页面布局,这个过程就是回流。)
      // elB.getBoundingClientRect()
      // elB.style.height = h + 'px'

      // 方式二、在 requestAnimationFrame 的回调函数中进行DOM操作,如改变元素的样式、尺寸或位置,这些操作会排队等待浏览器的下一个重绘周期,触发回流。
      requestAnimationFrame(() => {
        elB.style.height = h + 'px'
      })
    }
    elA.onmouseleave = () => {
      elB.style.height = 0
    }
  </script>
</body>

</html>

如有不足,欢迎指导。

尽可能设想多种解决方案,在多种解决方案中选择一种代价较少的最优解决方案。

  • 29
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值