实现一个有趣的水球加载进度动画

685 阅读3分钟

说在前面

今天来实现一个水球进度加载动画效果,整体是一个球形容器,球顶不断有水滴滴落,随着水滴滴落,底部水位不断上升,水面上涨的同时伴随着波动的动画。

在线体验

码上掘金

codePen

codepen.io/yongtaozhen…

代码实现

html

<div class="loader-container">
  <div class="wave-loader">
    <div class="wave wave1"></div>
    <div class="wave wave2"></div>
    <div class="percentage">0%</div>
  </div>
</div>
  • .loader-container:固定定位的全屏容器,用于覆盖整个页面,z-index: 9999确保层级最高
  • .wave-loader:水球容器,圆形设计( border-radius: 50% ),内部包含:
    • 两个 .wave 元素:双层波纹
    • .percentage:实时显示进度的文本元素

水球容器

.wave-loader {
  position: relative;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  overflow: hidden;
  box-shadow: 0 0 0 10px rgba(255, 255, 255, 0.05),
    0 0 20px rgba(108, 92, 231, 0.3);
}

使用 box-shadow 添加一个外发光和内阴影效果。

波浪效果

.wave {
  position: absolute;
  width: 200%;
  height: 200%;
  top: 50%;
  left: -50%;
  transform-origin: 50% 50%;
  animation: wave 6s linear infinite;
}

.wave1 {
  background: rgba(108, 92, 231, 0.8);
  border-radius: 45%;
  animation-duration: 6s;
}

.wave2 {
  background: rgba(0, 206, 255, 0.6);
  border-radius: 40%;
  animation-duration: 8s;
  top: 60%;
}

设置不同的 border-radius 值,模拟不同形态的波浪(椭圆度差异),两层不同颜色的波浪形成了一个立体感。

波浪动画

.wave1 {
  animation-duration: 6s;
}

.wave2 {
  animation-duration: 8s;
}
@keyframes wave {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

给两个波浪加上旋转动画,两个动画的速度差可以让波浪更加有层次感。

加载进度

.percentage {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: white;
  font-family: sans-serif;
  font-size: 2rem;
  font-weight: bold;
  z-index: 10;
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}

通过 text-shadow 给文字简单加个发光效果。

水滴滴落动画

水滴和涟漪样式

.drop {
  position: absolute;
  width: 8px;
  height: 12px;
  transform-origin: center;
  opacity: 0;
  background: linear-gradient(
    180deg,
    rgba(0, 206, 255, 0.9),
    rgba(108, 92, 231, 0.9)
  );
  border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
  box-shadow: 0 0 5px rgba(255, 255, 255, 0.3);
}

.ripple {
  position: absolute;
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  transform-origin: center;
  opacity: 0;
}

创建水滴元素

function createDrop() {
  const drop = document.createElement("div");
  drop.style.left = `${Math.random()*80+10}%`; // 随机水平位置(10%-90%)
  // 重力模拟动画
  let velocity = 0, position = -15; // 初始位置在容器外上方
  const waterLevel = 100 - progress; // 水面高度由进度决定
  // 实时计算下落位置,到达水面后触发涟漪
  if (position >= waterLevel * height / 100 - 5) {
    createRipple(x, waterLevel); // 创建涟漪
  }
}

涟漪效果

function createRipple(xPercent, y) {
  const ripple = document.createElement("div");
  // 涟漪扩散动画
  ripple.style.width = ripple.style.height = "0"; // 初始尺寸为0
  setTimeout(() => {
    ripple.style.width = `${size}px`; // 逐渐扩大
    ripple.style.opacity = 0; // 透明度渐变消失
  }, 10);
}

源码

gitee

gitee.com/zheng_yongt…

github

github.com/yongtaozhen…


  • 🌟 觉得有帮助的可以点个 star~
  • 🖊 有什么问题或错误可以指出,欢迎 pr~
  • 📬 有什么想要实现的功能或想法可以联系我~

公众号

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

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

说在后面

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