最简可用spinner用div加CSS即可:设width/height、border(如4px solid #ccc)、border-top-color不同色、border-radius:50%、animation:spin 1s linear infinite;需同时定义@keyframes spin和@-webkit-keyframes spin,避免兼容问题。

HTML 里怎么加一个最简可用的 spinner 动画
直接用一个 <div> 配 CSS 就够了,不需要 JS、不用引入第三方库。浏览器原生支持,兼容性从 Chrome 30+、Firefox 16+、Safari 6.1+ 开始都稳。
常见错误是套用网上老代码,用了 @-webkit-keyframes 却没补全标准写法,导致 Safari 或新版 Edge 不动;或者写了 animation: spin 1s infinite 但忘了给元素设 border 或 width/height,结果啥也看不见。
- 用
border+border-radius: 50%拼出圆环,再用border-top-color: transparent留出缺口,旋转时就形成“流动”感 - 必须设
width和height,且推荐用em或固定px,避免父容器塌陷导致动画消失 - 动画关键帧要同时写标准版和带前缀版:
@keyframes spin和@-webkit-keyframes spin - 别用
transform: rotate()替代animation,那样没法自动循环,还得靠 JS 控制
CSS spinner 动画为什么转得卡顿或不居中
卡顿通常是因为用了 left/top + transition 模拟旋转,或者在大列表里批量渲染几十个 spinner 导致重绘压力大;不居中则多因父容器没设 position: relative,或子元素没用 position: absolute 配 top: 50%; left: 50%; transform: translate(-50%, -50%)。
- 优先用
animation+transform: rotate(),GPU 加速更稳,比改border-color或box-shadow效果更可靠 - 居中时如果父容器是 flex 布局,直接给 spinner 加
margin: auto更轻量 - 在移动端要注意
will-change: transform可能引发闪烁,真卡顿时先去掉这行再测试 - Chrome DevTools 的 Rendering 面板里打开 “FPS Meter”,能直观看到是否掉帧
怎么让 spinner 在 fetch 请求期间自动显示/隐藏
核心不是“怎么动”,而是“什么时候动”。手动控制 display 或 visibility 容易漏掉异常分支(比如请求被 abort、网络中断、408 超时),导致 spinner 卡死在页面上。
立即学习“前端免费学习笔记(深入)”;
- 用
AbortController配合.finally()是最干净的写法:请求发起前 show,then和catch之后都执行 hide,finally里再统一收尾 - 别用
document.getElementById('spinner').style.display = 'block'这种硬编码,推荐加 class:spinner--active,CSS 控制显隐更可控 - 如果多个请求共用一个 spinner,需计数器(如
pendingCount++ / --),避免一个请求结束就提前隐藏 - 超时处理别只靠
setTimeout,fetch 本身支持signal,配合AbortController.timeout(5000)(Chrome 109+)更准确
Tailwind 或 Bootstrap 项目里要不要自己写 spinner
要看你用的版本。Tailwind v3.3+ 内置了 animate-spin,Bootstrap 5.3+ 有 <div class="spinner-border">,但默认配色和尺寸可能和你设计稿对不上,而且它们生成的 DOM 结构固定,不好微调旋转速率或 gap 大小。
- Tailwind 的
animate-spin底层就是animation: spin 1s linear infinite,你可以覆盖@layer utilities重定义spin关键帧来调速 - Bootstrap 的
spinner-border依赖border-width和width/height计算比例,改border-width: 2px同时得调width: 2rem,否则变形 - 如果项目已用 UnoCSS 或 Windi CSS,直接写
animate-[spin_0.8s_linear_infinite]更灵活,不用额外定义 - 真正省事的做法:只在按钮加载态用框架自带的,全局 loading 层(比如遮罩里的 spinner)还是手写,方便统一主题色和响应式缩放
最麻烦的其实是动画结束后加个淡出过渡——很多人忘了 spinner 元素本身也要做 opacity 动画,不然 hide 时突兀闪退。这个细节,八成人在联调时才意识到。


















