跳到主要内容

用纯 CSS 写 loading 动画:spinner、进度条、骨架屏一次讲透

不用图片、不用 JS,单靠 @keyframes 和几行 CSS 就能做出转圈 spinner、进度条和骨架屏。本文带你看懂原理、抄一段可直接用的转圈代码,把等待体验做得稳而不焦躁。

发布于 作者 李雷
#css #loading #前端 #动画

用纯 CSS 写 loading 动画:spinner、进度条、骨架屏一次讲透

页面在等接口、按钮在等提交、列表在等数据,这几秒钟里屏幕上摆什么,直接决定用户觉得你的产品快还是慢。很多人第一反应是去 npm 找个加载库,或者塞一张 GIF。其实绝大多数 loading 效果,纯 CSS 加几行 @keyframes 就够了,不用图片,不用 JavaScript 运行时,体积常常只有几百字节。

下面我把转圈 spinner、进度条、骨架屏三类讲清楚,给一段可以直接抄走的转圈代码,再说说什么场景该用哪一类。

为什么纯 CSS 比图片或 JS 更划算

一张 loading GIF 通常十几 KB 起步,缩放还会糊;引一个动画库为了一个 spinner 多打十几 KB 的 JS,也不值。纯 CSS 的 loader 不一样:它就是几条 CSS 规则加一段 @keyframes,浏览器原生渲染,不占主线程,SSR 页面、静态 HTML、邮件模板、MDX 文章里都能直接动起来,零依赖。

更关键的是可控。颜色、大小、速度全是 CSS 字面量,改一个数字就生效,不用重新打包,不用回工具里重导。

@keyframes 是怎么让圆圈转起来的

转圈 spinner 的核心只有两步。第一步,用 @keyframes 定义一段从 0 度转到 360 度的旋转:

@keyframes l-spin {
  to { transform: rotate(360deg); }
}

to 是终点关键帧,等价于 100%,意思是动画结束时元素正好转满一圈。浏览器会自动补齐中间每一帧的角度。

第二步,把这段动画挂到元素上,用 animation 指定时长和无限循环。圆圈本身用 border 画:四条边都给浅色,只有顶边给深色,转起来就成了大家熟悉的「缺口转圈」。

一个可以直接抄走的转圈 spinner

这是一段完整、纯 CSS、可直接粘进项目的 36px 转圈 loader:

<span class="l-spinner"></span>
.l-spinner {
  width: 36px;
  height: 36px;
  border: calc(36px / 9) solid #e5e7eb;   /* 浅色底圈 */
  border-top-color: #2563eb;               /* 深色缺口 */
  border-radius: 50%;
  animation: l-spin 0.9s linear infinite;
}
@keyframes l-spin {
  to { transform: rotate(360deg); }
}

三个能调的点:width / height 改大小,内部边框用 calc() 按比例算所以会自动跟着缩放;border-top-color 改主色;0.9s 改速度,数字调大就转得慢。linear 让它匀速转,别用缓动,否则一圈里忽快忽慢会显得卡。

进度条和骨架屏:换个思路用同一套原理

进度条不确定要加载多久时,做一个「不确定进度」的来回滑块最稳:用一个窄高亮块,靠 @keyframes 把它的 transform: translateX(...) 从左推到右、再循环,底色保持不动。用户看到东西在动,就知道系统没卡死。

骨架屏则是另一种思路:不转圈,而是先把最终内容的灰色轮廓摆出来(头像一个圆、标题一条、正文几条),再用一段慢扫光(@keyframes 平移一个线性渐变)在上面来回扫,营造「正在填充」的感觉。它的 @keyframes 动的是渐变背景位置,不是旋转。

我自己踩过的一个坑

我以前给一个首屏整页 loading 直接套了按钮里那个 0.6 秒的小 spinner,放大到 72px 之后,转得飞快,同事第一反应是「是不是哪里报错死循环了」。后来才明白:小尺寸快转显得利落,大尺寸快转显得慌张。大于 48px 的 loader 我现在一律放慢到 1.4 到 2 秒一圈,读起来才稳。同理,骨架屏的扫光也别太快,1.6 秒左右那种缓慢的扫过最不让人焦躁。

什么时候用哪一类

按钮里的异步操作,用 24 到 32px 的小 spinner 或三点动画,速度 0.8 到 1.2 秒。整页或首屏启动,用稍大的环或脉冲,配 1.4 到 2 秒的慢速。展示具体内容(信息流、个人主页、表格)且等待在 500ms 到 5s 之间,用骨架屏,因为它提前预览了版面结构,感知等待比转圈更短。等待快于 300ms 的就别上任何动画,一闪而过只会显得抖。

想省去手写每一条规则、直接挑一款调好颜色大小速度再复制代码,可以用 CSS 加载动画生成器,里面有 40 多款 spinner、骨架屏、进度条,全是纯 CSS。如果你想再深入理解 @keyframes 本身,从头自定义一段属于自己的动画,可以配合 CSS 关键帧动画生成器一起用。

把这几行 CSS 用熟,你会发现大多数等待场景根本不需要图片,也不需要任何 JS,几条规则就把体验做扎实了。


Made by Toolora · Updated 2026-06-13