正方体翻滚Loading动画

0 阅读4分钟

说在前面

🎈大家在做页面的时候,loading 基本都绕不开,转圈圈我们看多了,今天就来实现一个不一样的正方体翻滚 loading 动画。

效果展示

codepen

在线体验:codepen.io/yongtaozhen…

码上掘金

在线体验:code.juejin.cn/pen/7638926…

实现代码

1、先搭好结构

轨道 + 立方体 + 阴影 + 进度条

先把 DOM 骨架搭起来,核心是 .cube 里放 3 个面(正面、右侧、顶部),再加阴影和进度条区域。

<div class="loader" aria-label="正方体原地向右翻滚 loading">
  <span class="track"></span>
  <span class="shadow"></span>
  <span class="contact-shadow"></span>

  <div class="cube">
    <span class="face front"></span>
    <span class="face right"></span>
    <span class="face top"></span>
  </div>

  <div class="progress-wrap">
    <span class="progress-label">Loading</span>
    <span class="progress-rail"><span class="progress-fill" id="progress-fill"></span></span>
    <span class="progress-num" id="progress-num">0%</span>
  </div>
</div>

这里的关键点:

  • .loader 提供 perspective,让 3D 变换有空间感。
  • .cube 开启 transform-style: preserve-3d,子元素才能保持 3D 位置。
  • 轨道和阴影分层,后面动画同步会更自然。

2、做出立方体

3 个面拼出“可读”的 3D 体块

立方体不是一整块图片,而是 3 个面通过 translateZ / rotateX / rotateY 拼出来。

.cube {
  width: 72px;
  height: 72px;
  transform-style: preserve-3d;
  transform: translateY(0px) rotateX(-8deg) rotateY(8deg) rotateZ(0deg);
}

.front { transform: translateZ(36px); }
.right { transform: rotateY(90deg) translateZ(36px); }
.top   { transform: rotateX(90deg) translateZ(36px); }

为什么只放 3 个面?

  • 这个视角里,主要可见面就是 front/right/top。
  • 少渲染几个面,性能更稳。
  • 再配合渐变和内阴影,视觉上已经足够“像一个金属方块”。

3、做滚动节奏

关键帧里“抬起 + 落地 + 旋转 90°”

最关键的是 @keyframes roll-right。每次翻滚都不是匀速平转,而是:

  1. 抬起(translateY(-14px)
  2. 旋转到下一边(rotateZ +90deg
  3. 落地停一下(让节奏更像“滚”)
@keyframes roll-right {
  0% { transform: translateY(0px) rotateX(-8deg) rotateY(8deg) rotateZ(0deg); }
  11% { transform: translateY(-14px) rotateX(-8deg) rotateY(8deg) rotateZ(46deg); }
  22% { transform: translateY(0px) rotateX(-8deg) rotateY(8deg) rotateZ(92deg); }
  28% { transform: translateY(0px) rotateX(-8deg) rotateY(8deg) rotateZ(90deg); }
  100% { transform: translateY(0px) rotateX(-8deg) rotateY(8deg) rotateZ(360deg); }
}

这套百分比节点的作用,就是让动画从“转圈圈”变成“有重心变化的翻滚”。

4、阴影同步

让“重量感”真实起来

只做方块旋转会有点“飘”,所以再加两层阴影:

  • (1) shadow:大阴影,模拟整体投影。
  • (2) contact-shadow:接触阴影,强调落地那一瞬间。
@keyframes shadow-sync {
  0%, 22%, 28%, 47%, 53%, 72%, 78%, 97%, 100% { transform: scaleX(0.9); opacity: 0.5; }
  11%, 37.5%, 62.5%, 87.5% { transform: scaleX(0.78); opacity: 0.34; }
}

@keyframes contact-sync {
  0%, 22%, 28%, 47%, 53%, 72%, 78%, 97%, 100% { transform: scaleX(0.98); opacity: 0.6; }
  11%, 37.5%, 62.5%, 87.5% { transform: scaleX(0.74); opacity: 0.24; }
}

当正方体“抬起”时阴影变小、变淡;落地时恢复,这样肉眼会觉得它是有重量的。

5、进度条逻辑

这里只是模拟一下进度加载过程,实际还要根据业务接口返回的具体进度来进行渲染

这里我拆成两段:

  • (1)快速阶段:12 秒冲到 80%。
  • (2)慢速阶段:每 2 秒 +1%,直到 100%。
const FAST_TARGET = 80;
const FAST_DURATION_MS = 12000;
const SLOW_STEP_MS = 2000;

const startFastPhase = () => {
  const start = performance.now();
  const tick = (now) => {
    const t = Math.min(1, (now - start) / FAST_DURATION_MS);
    value = Math.floor(t * FAST_TARGET);
    render(value);
    if (t < 1) requestAnimationFrame(tick);
    else startSlowPhase();
  };
  requestAnimationFrame(tick);
};

源码地址

gitee

源码地址:gitee.com/zheng_yongt…

github

源码地址:github.com/yongtaozhen…


🌟 觉得有帮助的可以点个 star~

🖊 有什么问题或错误可以指出,欢迎 pr~

📬 有什么想要实现的功能或想法可以联系我~

公众号

关注公众号『 前端也能这么有趣 』,获取更多有趣内容。

发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。