跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
HTML / CSS大前端

CSS 7球旋转加载动画:实现与避坑

用 HTML 和 CSS 实现一个 7 小球绕圈旋转的加载动画,核心技巧是 transform-origin 和 animation-delay 错开启动。文章展示了多种变体(跳跃、渐隐、色彩流动等),并分享了移动端性能优化、动画结束状态控制、CSS 变量管理等实际经验。适量加载动画能缓解等待焦虑,但超时控制和骨架屏才是终极方案。

暖阳发布于 2026/6/160 浏览
CSS 7球旋转加载动画:实现与避坑

7球旋转加载动画

加载动画说到底是为了让用户安心。点完按钮页面没反应,多半会以为挂了。放几个转圈的小球,至少能告诉对方'服务器还在,只是慢了点'。这种 7 球绕圈效果经典、轻量,而且兼容性没得说。

HTML 结构

别急着写 CSS,先把结构定清楚。用 ul 或 div 包 7 个子元素都行,但记得加无障碍标记。装饰性动画不需要被读屏软件反复念叨,给容器挂上 aria-hidden="true",再塞一个给屏幕阅读器看的文字说明,用 sr-only 藏起来就行。

<div class="loading-container" aria-label="正在加载数据" role="status">
  <div class="loading-wrapper" aria-hidden="true">
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div class="dot"></div>
    <div =>
    
  
  加载中,请稍候...

class
"dot"
</div>
<div class="dot">
</div>
</div>
<span class="sr-only">
</span>
</div>

核心 CSS

核心就三个东西:transform-origin 定旋转中心,animation 控制节奏,@keyframes 画轨迹。要让小球看起来像接力,靠的是 animation-delay 错开启动。我把周期设成 1.4 秒,每个球延迟 0.2 秒,7 个刚好一圈。不是强制的,你按自己节奏调。

.loading-wrapper {
  position: relative;
  width: 60px;
  height: 60px;
  /* 开启硬件加速 */
  transform: translate3d(0, 0, 0);
}

.dot {
  position: absolute;
  width: 12px;
  height: 12px;
  background: #3498db;
  border-radius: 50%;
  /* 变换中心定在容器中心 */
  transform-origin: 30px 30px;
  /* 初始位置 */
  transform: rotate(0deg) translateY(-25px);
  animation: rotate 1.4s ease-in-out infinite;
}

/* 利用 nth-child 错开延迟 */
.dot:nth-child(1) { animation-delay: 0s; }
.dot:nth-child(2) { animation-delay: 0.2s; }
.dot:nth-child(3) { animation-delay: 0.4s; }
.dot:nth-child(4) { animation-delay: 0.6s; }
.dot:nth-child(5) { animation-delay: 0.8s; }
.dot:nth-child(6) { animation-delay: 1.0s; }
.dot:nth-child(7) { animation-delay: 1.2s; }

@keyframes rotate {
  0% {
    transform: rotate(0deg) translateY(-25px) scale(1);
    opacity: 1;
  }
  50% {
    /* 转到对面缩小增加立体感 */
    transform: rotate(180deg) translateY(-25px) scale(0.6);
    opacity: 0.5;
  }
  100% {
    transform: rotate(360deg) translateY(-25px) scale(1);
    opacity: 1;
  }
}

用 ease-in-out 比 linear 的机械感好很多,小球动起来更自然。

变体

同样的结构,稍微改改 @keyframes 就能变出不同风格。下面是我在不同场景下常用的几种,不一定全用到,知道原理就行。

跳跃式

适合活泼的页面,在旋转的同时改变大小和纵向偏移。

.dot-jump {
  position: absolute;
  width: 10px;
  height: 10px;
  background: #e74c3c;
  border-radius: 50%;
  transform-origin: 30px 30px;
  animation: jump 1.4s ease-in-out infinite;
}

/* 颜色与延迟设置略 */

@keyframes jump {
  0%, 100% {
    transform: rotate(0deg) translateY(-25px) scale(1);
  }
  25% {
    transform: rotate(90deg) translateY(-35px) scale(1.3);
  }
  50% {
    transform: rotate(180deg) translateY(-25px) scale(0.8);
  }
  75% {
    transform: rotate(270deg) translateY(-30px) scale(1.1);
  }
}

渐隐渐现

比较克制,适合严肃的商务场景,像呼吸灯一样。

.dot-fade {
  position: absolute;
  width: 12px;
  height: 12px;
  background: #95a5a6;
  border-radius: 50%;
  transform-origin: 30px 30px;
  animation: fade 1.2s linear infinite;
  opacity: 0.2;
}

@keyframes fade {
  0%, 100% {
    opacity: 0.2;
    transform: rotate(0deg) translateY(-25px) scale(1);
  }
  50% {
    opacity: 1;
    transform: rotate(180deg) translateY(-25px) scale(1.2);
  }
}

颜色流动

用 CSS 变量或 hue-rotate() 让颜色跟着转动变化,多用于品牌色丰富的界面。

.dot-color {
  position: absolute;
  width: 12px;
  height: 12px;
  background: hsl(calc(var(--i) * 51), 70%, 50%);
  border-radius: 50%;
  transform-origin: 30px 30px;
  animation: colorFlow 2s ease-in-out infinite;
}

@keyframes colorFlow {
  0% {
    transform: rotate(0deg) translateY(-25px);
    filter: hue-rotate(0deg);
  }
  50% {
    transform: rotate(180deg) translateY(-25px);
    filter: hue-rotate(180deg);
  }
  100% {
    transform: rotate(360deg) translateY(-25px);
    filter: hue-rotate(360deg);
  }
}

弹性拉伸

用 cubic-bezier 调出弹力感,游戏类页面很常见。

.dot-elastic {
  position: absolute;
  width: 10px;
  height: 10px;
  background: #e91e63;
  border-radius: 50%;
  transform-origin: 30px 30px;
  animation: elastic 1.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
}

@keyframes elastic {
  0% {
    transform: rotate(0deg) translateY(-25px) scale(1);
  }
  25% {
    transform: rotate(90deg) translateY(-25px) scaleX(1.5) scaleY(0.6);
  }
  50% {
    transform: rotate(180deg) translateY(-25px) scaleX(0.6) scaleY(1.5);
  }
  75% {
    transform: rotate(270deg) translateY(-25px) scaleX(1.3) scaleY(0.7);
  }
  100% {
    transform: rotate(360deg) translateY(-25px) scale(1);
  }
}

反向旋转

奇数球正转、偶数球反转,视觉上有点错乱的美感。

.dot-reverse:nth-child(odd) {
  background: #3498db;
  animation: rotateCW 2s linear infinite;
}

.dot-reverse:nth-child(even) {
  background: #2ecc71;
  animation: rotateCCW 2s linear infinite;
}

@keyframes rotateCW {
  from { transform: rotate(0deg) translateY(-25px); }
  to { transform: rotate(360deg) translateY(-25px); }
}

@keyframes rotateCCW {
  from { transform: rotate(360deg) translateY(-25px); }
  to { transform: rotate(0deg) translateY(-25px); }
}

大小交替

奇数球放大、偶数球缩小,自带节奏感。

.dot-breathe:nth-child(odd) {
  background: #9b59b6;
  animation: breatheBig 1.4s ease-in-out infinite;
}

.dot-breathe:nth-child(even) {
  background: #f39c12;
  animation: breatheSmall 1.4s ease-in-out infinite;
}

@keyframes breatheBig {
  0%, 100% {
    transform: rotate(0deg) translateY(-25px) scale(1.5);
    opacity: 0.8;
  }
  50% {
    transform: rotate(180deg) translateY(-25px) scale(0.8);
    opacity: 0.4;
  }
}

@keyframes breatheSmall {
  0%, 100% {
    transform: rotate(0deg) translateY(-25px) scale(0.6);
    opacity: 0.4;
  }
  50% {
    transform: rotate(180deg) translateY(-25px) scale(1.2);
    opacity: 0.9;
  }
}

暂停呼吸

鼠标悬停时动画暂停,小球放大,给一点反馈。

.dot-pause {
  position: absolute;
  width: 12px;
  height: 12px;
  background: #1abc9c;
  border-radius: 50%;
  transform-origin: 30px 30px;
  animation: rotate 1.4s ease-in-out infinite;
  animation-play-state: running;
  transition: transform 0.3s ease;
}

.loading-wrapper:hover .dot-pause {
  animation-play-state: paused;
  transform: scale(1.2) !important;
}

碰过的坑

移动端卡顿:低端安卓机上,filter 和复杂 transform 容易触发重绘。我习惯给容器加 transform: translate3d(0, 0, 0),强制硬件加速。will-change 也能用,但用完记得取消,不然内存会慢慢涨上去。

动画结束后小球停得歪:加载完了 JS 把 loading 移除,小球可能卡在半空。这时候 animation-fill-mode: forwards 管用,提前设好结束状态。

小球对不齐:别手动调 margin,直接用 flex 或 grid 居中。

.loading-wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

颜色难统一:把颜色、大小、时长抽成 CSS 变量,一处改全换,深色模式适配也方便。

:root {
  --dot-base-color: #3498db;
  --dot-size: 12px;
  --animation-duration: 1.4s;
}

.dot {
  width: var(--dot-size);
  height: var(--dot-size);
  background: var(--dot-base-color);
  animation-duration: var(--animation-duration);
}

上线前的自查

  • 容器一定挂到特定 div 下,别直接放 body;路由跳转时记得销毁,不然动画在后台一直跑。
  • 避免 FOUC:默认隐藏,等 JS 准备好再淡入。
  • 设最大显示时间,超过 10 秒最好给个超时提示,别让用户傻等。
  • 深色模式下背景色可能吞掉小球,要么用 currentColor,要么在媒体查询里换个亮色。
  • 不要一上来就显示 loading,接口响应 300ms 以内的时候闪一下反而不舒服。先用变量记一下时间,超了再展示。

说到底,loading 只是缓兵之计,接口慢得离谱的话加个骨架屏或分批加载才是正经。

再加点花样

随机延迟:用 calc() 加一点偏移,比死板的 0.2 秒更生动。

.dot:nth-child(2) {
  animation-delay: calc(var(--base-delay) * 1 + 0.05s);
}

hover 炸开:配合 transition 比纯 animation 更柔和,小球悬停时散开。

.dot-interactive {
  transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.loading-wrapper:hover .dot-interactive:nth-child(1) {
  transform: rotate(0deg) translateY(-40px) scale(1.5);
}

文字提示联动:如果还要带'加载中...'的省略号动画,可以这么玩。

.loading-text::after {
  content: '...';
  animation: dots 1.5s steps(4, end) infinite;
}

@keyframes dots {
  0%, 20% { content: '.'; }
  40% { content: '..'; }
  60% { content: '...'; }
  80%, 100% { content: ''; }
}

基本就是这些。前端动画很多时候是细节堆出来的,没必要一次性全用上,挑适合自己项目的就好。

目录

  1. HTML 结构
  2. 核心 CSS
  3. 变体
  4. 跳跃式
  5. 渐隐渐现
  6. 颜色流动
  7. 弹性拉伸
  8. 反向旋转
  9. 大小交替
  10. 暂停呼吸
  11. 碰过的坑
  12. 上线前的自查
  13. 再加点花样
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 几个值得收藏的AI提示词平台
  • C++11右值引用与移动语义:从深拷贝到资源转移的实战理解
  • 从焦虑到掌控:AI 时代的超级能动性与系统思维
  • 将 Figma 设计稿自动转为前端代码:MCP + Figma AI Bridge 上手
  • 2026年毕业论文AIGC检测:各院校AI率及格线怎么定
  • C++26 任务优先级调度机制解析
  • 搞定AI Agent开发:3个月学习路线与面试经验
  • 把Spine拆件补图从一周压缩到两小时:AIGC+Photoshop实操记录
  • M2FP 拼图算法:打通多人人体解析的最后一步
  • Spring Boot RESTful API 分层开发与测试实战
  • C++11 关键新特性回顾与实践
  • OpenClaw:更名、进化与意外走红
  • 让高斯动起来:3DGS 动态渲染的取舍与实操
  • 用 Mem0 给大模型装上记忆:不只是 RAG 的替代品
  • LLM 微调:时机、方法与抉择
  • 离线安装 python-docx:给 Python 3.8.8 用户的一些步骤
  • 用海螺AI把图片变成视频:MiniMax图生视频上手记录
  • Fooocus部署手记:从手动配置到云上一键部署
  • ToClaw 上手:当 AI 开始在桌面上替你执行任务
  • 网络安全从业者常用的9款工具
  • 相关免费在线工具

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

    • HTML转Markdown

      将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

    • JSON 压缩

      通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

    • JSON美化和格式化

      将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online