最简纯css加载动画需两步:定义@keyframes旋转帧并绑定animation;关键细节包括用border-top-color配合transparent实现单色弧线、加border-radius:50%、硬件加速修复safari闪烁、aspect-ratio自适应、visibility+opacity平滑隐藏。

用 @keyframes + animation 实现最简 loading 圆圈
纯 CSS 加载动画核心就两步:定义旋转帧、绑定到元素。不需要 JS,也不依赖外部资源。
常见错误是直接给 border 加 animation,但默认不生效——因为 border 不是独立可动画属性,得用 border-top-color 或整个 border 配合 transparent 才能出“旋转缺口”效果。
推荐写法:
.loader {
width: 40px;
height: 40px;
border: 4px solid #eee;
border-top-color: #333;
border-radius: 50%;
animation: spin 1s linear infinite;
}
<p>@keyframes spin {
to { transform: rotate(360deg); }
}</p>
-
border设为四边同色,再单独覆盖border-top-color,形成视觉上的“单色弧线” -
border-radius: 50%必须加,否则是方框转圈 - 动画时长建议
0.8s–1.2s,太慢显卡顿,太快像闪屏
避免 transform: rotate() 在 Safari 上闪烁
Safari(尤其是 iOS 15–16)对纯 transform 动画渲染不稳定,可能偶发掉帧或白屏闪动。
解决方法不是换动画类型,而是加硬件加速提示:
.loader {
transform: rotate(0deg);
transform-style: preserve-3d; /* 关键 */
backface-visibility: hidden; /* 关键 */
}
- 只加
transform: translateZ(0)也行,但不如上面两个属性兼容性稳 - 不要滥用
will-change: transform,它在低内存设备上反而拖慢首帧 - 这个修复对 Chrome/Firefox 无害,可全端写上
让 loading 动画随父容器大小自适应
固定 width/height 在响应式布局里很脆弱,尤其用在按钮或卡片内部时。
更健壮的做法是用 aspect-ratio + min-width:
.loader {
aspect-ratio: 1;
min-width: 1em;
border: 0.15em solid #eee;
border-top-color: currentColor;
animation: spin 1s linear infinite;
}
-
aspect-ratio: 1保证永远是正圆,不用管宽高是否相等 -
min-width: 1em让它随父级字体大小缩放(比如父级设了font-size: 12px,loader 就是 12px 宽) -
border用em单位,border-top-color: currentColor可继承文字色,方便主题切换
加载完成时如何平滑隐藏动画
直接 display: none 会突兀消失,用户可能没意识到操作已结束;用 opacity: 0 又占文档流位置。
正确做法是结合 visibility 和 opacity,并控制过渡时机:
.loader {
opacity: 1;
visibility: visible;
transition: opacity 0.2s ease, visibility 0.2s;
}
<p>.loader.hide {
opacity: 0;
visibility: hidden;
}</p>
- 必须同时设
visibility: hidden和opacity: 0,否则opacity: 0仍可点击或影响 tab 键顺序 - transition 不要加
all,只声明具体属性,避免意外触发其他 CSS 变化 - JS 控制时,先加
.hide类,别用setTimeout去 remove,容易和动画时间错拍
真正难的不是画个转圈,而是让它在各种尺寸、主题、浏览器和状态切换中都不出戏。细节比如 backface-visibility 或 visibility + opacity 组合,恰恰是上线后被 QA 抓出来的高频问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











