✨✨做一个伪3D效果的卡片列表来复习一下CSS动画吧~

简介: ✨✨做一个伪3D效果的卡片列表来复习一下CSS动画吧~

前言


本来是准备接着前面做的那个 使用SVG实现动态分布的圆环发散路径动画 的效果,希望通过 纯 Div + CSS 的方式来实现。但是目前看起来进度比较缓慢,虽然做出来了大致样式,但是动画还没加上,所以得后面再继续弄。


今天主要是通过写一个 “伪3D” 的卡片组效果,顺道也复习一下基础的 CSS 动画。


因为作者平时都是写的后台管理的项目,所以接触 CSS 动画之类的东西也比较少,实现方式和效果看起来可能没有那么好,希望大家多多包涵。


开始


本身这里最初的设想是希望 像打牌那样的初始效果,然后 通过点击卡片抽出单张选中卡片预览,再加上一些简单的过渡动画。不过后来又觉得 直接做成平铺列表然后选中卡片移动到最右侧 的效果也行,所以干脆都加上算了。


当然为了保证正确的层级关系,还是使用了 定位配合 zIndex 来确定每个卡片的 层级顺序和位置


卡片的排列模式也是通过一个变量来确定的,然后增加了一个切换按钮,后面如果有需要的话改成 props 配置也行。


话不多说,直接开干吧。


模拟数据


当然,在开始之前肯定要 模拟一个卡片数组 cards 与一个排列模式变量 clutter


data() {
  return {
    activeIndex: -1,
    clutter: true, // 杂乱
    cards: []
  };
},
created() {
  this.initData();
},
methods: {
  initData() {
    const arr = new Array(12).fill(1);
    this.cards = arr.map((_, index) => {
      return this.computedStyle(index, 12);
    });
  },
  resetData() {
    this.clutter = !this.clutter;
    this.initData();
  },
  computedStyle(index, length) {
    const clutter = this.clutter;
    const defaultStyles = {
        "--max-index": length + 1,
        "--bg-color": randomRgbColor(),
        "--card-index": index
    };
    return defaultStyles;
  }
}


这里的 initDataresetData 肯定就不需要介绍啦,就是重置和切换排列模式,当然因为改变排列模式后样式也有改动,所以在resetData 中也重新调用了initData来重新生成卡片数组。


至于computedStyle则是 计算每个卡片的样式并返回样式结果的,不管什么排列模式下 这几个 CSS 变量都是必须且固定的,所以就先放上来了。


data 中的activeIndex 则是代表当前激活的卡片下标的。


键盘事件


这里的初衷是为了方便 快速切换激活卡片、在卡片太多时也可以减少误触


这里唯一注意的一点就是,在执行键盘监听事件的时候,需要判断一下当前的 focus 元素,如果是在一些可聚集的元素中则不能触发翻页


mounted() {
  let addIndex = () => {
    if (this.activeIndex < this.cards.length - 1) {
      this.activeIndex++;
    } else {
      this.activeIndex = 0;
    }
  };
  let lessIndex = () => {
    if (this.activeIndex > 0) {
      this.activeIndex--;
    } else {
      this.activeIndex = this.cards.length - 1;
    }
  };
  let keyboardDeal = (e) => {
    if (document.activeElement !== document.body) return;
    // 方向键--上
    if (e.keyCode === 38) {
      addIndex();
    }
    // 方向键--下
    if (e.keyCode === 40) {
      lessIndex();
    }
    // 方向键--左
    if (e.keyCode === 37) {
      lessIndex();
    }
    // 方向键--右
    if (e.keyCode === 39) {
      addIndex();
    }
  };
  window.addEventListener("keyup", keyboardDeal);
  this.$on("hook:beforeDestroy", () => {
    window.removeEventListener("keyup", keyboardDeal);
  });
},


另外,这里通过 this.$on("hook:beforeDestroy") 来注册组件 在销毁之前需要执行的回调函数功能与选项式 API 中的 beforeDestroy 配置项功能一致


在组件即将销毁时,会清除掉组件中的键盘监听事件。


通过document.activeElement 是否等于 body 元素,来确定当前焦点位置。一般只有在该属性等于body的时候,才代表当前页面中没有其他聚焦元素,可以正常执行我们定义的按键翻页。


模板


至于 html 部分,倒是没有太多细节的内容,仅仅只是 Vue 的遍历语法和动态样式两个知识点,相信大部分同学都很清楚。


<template>
  <div class="AnimationCards">
    <h1>AnimationCards Page</h1>
    <p>
      <el-button @click="resetData">乱序</el-button>
    </p>
    <div class="demo-content">
      <div class="animation-cards-box">
        <div
          v-for="(styles, index) in cards"
          :class="[
            'animation-card',
            { 'is-active': activeIndex === index, 'is-clutter': clutter, 'is-list': !clutter }
          ]"
          :key="index"
          :style="styles"
          @click="activeIndex = activeIndex === index ? -1 : index"
        >
          <span>Card {{ index }}</span>
        </div>
      </div>
    </div>
  </div>
</template>


这里动态绑定的 is-clutter 和 is-list 其实也可以放到父级 animation-cards-box 中


至于每个 card 元素动态绑定的 style,里面有定义好的 CSS 变量,提供给每个卡片的动画和默认样式使用。这个用法我在之前的文章中也提到过,标签的内联样式也可以直接声明 CSS 变量


样式与动画


因为采用了两种排列方式,每种排列方式的动画都不一样,所以样式和动画都有不同

但是因为共同都是采用的定位来确定层级的,所以也有一样的地方。


下面这部分是一样的样式部分:


.animation-cards-box {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  padding: 20px;
  position: relative;
  .animation-card {
    width: 200px;
    background-color: var(--bg-color);
    border-radius: 8px;
    cursor: pointer;
    position: absolute;
    top: 20px;
    bottom: 20px;
    box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.8);
    transition: all ease-in-out 0.4s;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 32px;
    font-weight: bold;
    color: #ffffff;
    z-index: var(--card-index);
  }
}


通过上面模板部分绑定的 CSS 变量来确定具体样式。


列表状态


列表分布的状态下,所有卡片 依次向右排布,后面的卡片覆盖前面的卡片;在卡片被激活后,会移动到最右侧最顶层显示,大致效果如下:


网络异常,图片无法展示
|


1. 所以,首先是正常情况下的分布样式


.animation-card.is-list {
  &:hover {
    & ~ .animation-card {
      transform: translateX(24px);
    }
  }
  &.is-active {
    z-index: var(--max-index) !important;
    transform: translateX(calc(var(--max-index) * 20px - var(--card-index) * 20px - 40px));
  }
}


在 hover 时,所有 后面的兄弟节点会向右移动 20px;激活后(is-active),被激活的卡片会通过 zIndex 置顶,并通过 transform 向右平移到 最右侧


2. 然后,是 js 中的 computedStyle 样式计算,按顺序每个卡片向右移动 16 px(后面可以根据需求修改):


computedStyle(index, length) {
    const clutter = this.clutter;
    const defaultStyles = {
        "--max-index": length + 1,
        "--bg-color": randomRgbColor(),
        "--card-index": index
    };
    if (!clutter) defaultStyles["left"] = `${16 * ++index}px`;
    return defaultStyles;
}


3. 最后,是列表横向排布时的动画帧。


@keyframes eject {
  50% {
    transform: translateX(calc(-100% - 20px)) rotate(-20deg);
  }
}
@keyframes reject {
  50% {
    transform: translateX(calc(100% + 20px)) rotate(10deg);
  }
}


这里区分了 非激活 -> 被激活 的 eject从被激活 -> 非激活状态的 reject 两个动画:


  • eject :动画中间状态是 整体 向左偏移 整个卡片宽度加上 20px 的距离,并向左稍微旋转 20deg


  • reject :动画中间状态是 整体 向右偏移 整个卡片宽度加上 20px 的距离,并向右稍微旋转 10deg


另外eject的动画时间比reject 多一倍,也是为了把注意力集中在被激活卡片。


本身我是希望最后才把 zIndex 设置成最大值的,但是因为用了CSS变量的关系,动画帧定义不知道咋写了。如果有大佬知道也请告诉我一下,非常感谢~~


扇形乱序分布


这也是我里边说“乱序”状态吧,因为最初的一版卡片分布是按下标依次一左一右排列的,所以顺序有一点问题;不过后面也加了一个完整扇形的效果。


基础样式与列表状态一样,有区别的只是 激活/非激活的样式计算和动画定义部分


这个效果大概像这样:


网络异常,图片无法展示
|


1. 首先,一样是两个状态的样式定义:


.animation-card.is-clutter {
  transform: translateX(0%) rotate(var(--rotate-deg));
  transform-origin: bottom center;
  &.is-active {
    animation: rotation ease-in-out 0.8s;
    transform: translateX(calc(120%)) rotate(0deg);
    z-index: var(--max-index) !important;
  }
}


因为是 类似扇形的效果,需要保证旋转轴的位置在底部,所以需要设置 transform-origin


  • 正常状态 下,卡片只是稍微旋转


  • 被激活状态 下,卡片会平移到最后侧并取消旋转角度,同时置顶


2. 然后,是样式计算部分


computedStyle(index, length) {
  const clutter = this.clutter;
  const defaultStyles = {
    "--max-index": length + 1,
    "--bg-color": randomRgbColor(),
    "--card-index": index
  };
  if (clutter) {
    let rotate = 0;
    if (index % 2 === 1) {
      rotate = length - index;
    } else {
      rotate = index - length;
    }
    defaultStyles["--rotate-deg"] = rotate + "deg";
  }
  return defaultStyles;
}


根据下标的奇偶性,分别向左、向右旋转特定角度。


3. 最后,就是动画定义


这里为了方便,只定义了 从 非激活 -> 激活状态 的动画,取消激活时则是直接通过 transition 定义的一个过渡效果。


@keyframes rotation {
  0% {
    transform: translateX(0%) rotate(var(--rotate-deg));
  }
  60% {
    transform: translateX(calc(130%)) rotate(2deg);
  }
  70% {
    transform: translateX(calc(110%)) rotate(-2deg);
  }
  80% {
    transform: translateX(calc(125%)) rotate(1deg);
  }
  90% {
    transform: translateX(calc(115%)) rotate(-1deg);
  }
  100% {
    transform: translateX(calc(120%)) rotate(0deg);
  }
}


这里动画 初期依旧保持正常状态,到 60% 时到达目标区域,后面的过程就是一个轻微晃动的效果,在100% 时停留在目标位置。


扇形正序


早上突然发现,正序其实修改不大,只需要调整 computedStyle 方法即可。


computedStyle(index, length) {
  const clutter = this.clutter;
  const defaultStyles = {
    "--max-index": length + 1,
    "--bg-color": randomRgbColor(),
    "--card-index": index
  };
  const tangle = 48;
  const unitArc = tangle / length;
  if (clutter) {
    let rotate = unitArc * index - 48 / 2;
    defaultStyles["--rotate-deg"] = rotate + "deg";
  return defaultStyles;
}


这里的 tangle 是两边的最大旋转角度,可以根据需要自定义。unitArc 则是单位旋转角度,然后 初始角度 则是在左边 二分之一 tangle 的位置。


此时,显示效果就是这样了:


网络异常,图片无法展示
|


最后


当然本文个人感觉干货不是很多,只是在平时突然想到的一点儿小点子,但是动画效果其实不是很完美。只希望能给大家带来一点小小的灵感吧~~~

目录
相关文章
|
19天前
纯css3实现的百分比渐变进度条加载动画源码
纯css3实现的百分比渐变进度条加载动画特效源码
51 31
|
4天前
|
Web App开发 移动开发 JavaScript
纯CSS3+SVG实现的节日庆祝五彩纸屑动画效果源码
这是一款基于纯CSS3+SVG实现的节日庆祝五彩纸屑动画效果源码。画面中左下角是一个圆锥形礼炮卡通效果,呈现出节日庆祝时礼花爆破、五彩纸屑纷飞的动画特效。整体动画效果采用纯css3+svg实现,没有引入任何外部图形或js脚本元素。建议使用支持HTML5与css3效果较好的火狐(Firefox)或谷歌(Chrome)等浏览器预览本源码。
22 6
|
14天前
|
前端开发 JavaScript UED
CSS滚动效果和视差滚动的原理、应用及其对用户体验的影响。从平滑滚动到元素跟随,再到滚动触发动画
本文探讨了CSS滚动效果和视差滚动的原理、应用及其对用户体验的影响。从平滑滚动到元素跟随,再到滚动触发动画,这些效果增强了页面的吸引力和互动性。视差滚动通过不同层次元素的差异化移动,增加了页面的深度感和沉浸感。文章还讨论了实现方法、性能优化及案例分析,旨在为设计师和开发者提供实用指导。
36 7
|
19天前
CSS3制作的聚光灯下倒影文字选装动画特效源码
CSS3聚光灯下倒影文字特效是一段基于CSS3实现的聚光灯下带倒影的文字旋转动画效果代码,具有真实的视觉感,同时文字还会在旋转过程中显示出灯光的反射效果,很有意思,欢迎对此段代码感兴趣的朋友前来下载使用。
26 6
|
19天前
纯css3加载loading发光变色动画代码
纯css3加载loading发光变色动画特效代码是一款基于css3 keyframes属性实现的发光变色圆点串联旋转loading加载动画
21 2
|
20天前
|
Web App开发 前端开发 iOS开发
CSS加载动画大全 126种
CSS加载动画大全是一个css Loaders加载动画特效汇总,一共包含126种加载动画效果,不同样式不同图案,简单实用,一览包含所有,会让你在等待的过程中,体验视觉盛宴,给用户不一般的加载体验,欢迎下载试试!代码适用浏览器:搜狗、360、FireFox(建议)、Chrome、Safari、Opera、傲游、世界之窗,是一款不错的的特效插件,希望大家喜欢!
24 2
|
21天前
|
JavaScript 前端开发
CSS3 动画和 JavaScript 动画的性能比较
具体的性能表现还会受到许多因素的影响,如动画的复杂程度、浏览器的性能、设备的硬件条件等。在实际应用中,需要根据具体情况选择合适的动画技术。
|
7月前
|
前端开发 内存技术
CSS动画示例(上一篇是CSS过渡…)
CSS动画示例(上一篇是CSS过渡…)
|
7月前
|
前端开发
CSS3中的动画示例
CSS3中的动画示例
|
前端开发
css扫描动画效果demo示例(整理)
css扫描动画效果demo示例(整理)