纯css height auto支持过渡折叠动画

4,070 阅读2分钟

盒子折叠动画是一个比较常见的交互效果,比如:

动画.gif

<div class="fold">
    <button class="btn">按钮</button>
    <div class="content">
        测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
    </div>
</div>
      .fold {
        display: inline-block;
        position: relative;
      }

      .btn {
        width: 100px;
        height: 50px;
      }
      .content {
        width: 100px;
        height: 0;
        color: #fff;
        background-color: #4f4f4f;
        overflow: hidden;
        margin-top: 8px;
        transition: 0.3s;
        position: absolute;
        top: 60px;
      }

      .fold:hover .content {
        height: 150px;
      }

为了更加直观看清css逻辑,我把他简化为:

.content {
    ...
    height: 0;
}

 .fold:hover .content {
    height: 150px;
}

这个折叠交互效果是让content盒子的height=0到height=150px切换,中间有个0.3s的过度

但是日常开发中,content盒子内容有可能是动态变化的,显然这种把高度限制死的方法是不正确的。

一想到高度自适应,我们肯定会想到height: auto;,当让content盒子的height=0到height=auto切换时,就会发现会出现这样的效果:

动画.gif

.content {
    ...
    height: 0;
}

 .fold:hover .content {
    height: auto;
}

动画过渡没有了,原来transition实现高度过渡需要height设置具体的数值才行

有没有方法即让高度自适应,也要有动画过度呢,肯定是有的,下面就借助clip-path实现这个效果(当然还可以用js解决)

clip-path 是一个 CSS 属性,用于裁剪元素的显示区域。它允许你使用各种形状来定义一个裁剪区域,从而只显示该区域内的内容,而隐藏区域外的内容。

clip-path属性有很多常用的函数比如:inset、circle、ellipse、polygon等等,这里就不做过多介绍了,这里我们主要使用的是inset

inset() 函数的语法如下:

clip-path: inset(top right bottom left);

其中,toprightbottomleft 是用于定义裁剪区域的边界偏移值。这些值可以使用百分比或具体的长度单位(像素、em 等)。

  • top:定义裁剪区域上边界的偏移值。
  • right:定义裁剪区域右边界的偏移值。
  • bottom:定义裁剪区域下边界的偏移值。
  • left:定义裁剪区域左边界的偏移值。

想要直观看清这几个参数作用,可以去techbrood.com/tool?p=css-… 可视化调试一下,就知道这几个参数的作用了

把以上代码更改如下:

.content {
    ...
    height: auto;
    clip-path: inset(0 0 100% 0);
}

 .fold:hover .content {
    clip-path: inset(0);
}

动画.gif

源码:

<!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>
      body {
        width: 100vw;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    </style>
    <style>
      .fold {
        display: inline-block;
        position: relative;
      }

      .btn {
        width: 100px;
        height: 50px;
      }
      .content {
        width: 100px;
        height: auto;
        color: #fff;
        background-color: #4f4f4f;
        margin-top: 8px;
        transition: 0.3s;
        clip-path: inset(0 0 100% 0);
        position: absolute;
        top: 60px;
      }

      .fold:hover .content {
        clip-path: inset(0);
      }
    </style>
  </head>
  <body>
    <div class="fold">
      <button class="btn">按钮</button>
      <div class="content">
        测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
      </div>
    </div>
  </body>
</html>