纯CSS实现可靠loading动画的关键是置于开头并用内联样式定义,确保首帧即现;隐藏必须用window.load事件加8秒超时兜底,避免FOUC或卡死;需加transform:translateZ(0)等硬件加速属性保障Safari稳定渲染。

纯 CSS 就能做出可靠、不闪、首屏即现的 loading 动画,关键不是“怎么动”,而是“什么时候动、怎么不被浏览器吃掉”。
为什么写在 开头的 loading 会一闪而过或根本不出现
HTML 是自上而下解析的,但浏览器渲染受 CSSOM 和 JS 阻塞影响。常见失效场景:
-
<script></script>放在里且没加defer或async:JS 同步执行卡住 HTML 解析,#loading元素还没创建出来,页面就停了 - CSS 外链体积大或未内联关键样式:浏览器等 CSSOM 构建完才开始渲染,即使 DOM 有 loading 元素,也可能因无
position: fixed、z-index或背景色而不显示 - 用了
visibility: hidden或opacity: 0初始隐藏 body:loading 层可能被层级逻辑覆盖,尤其在 Safari 下更易失效
window.addEventListener('load', ...) 是唯一稳妥的隐藏时机
load 事件确保图片、字体、CSS、JS、iframe 等所有资源加载完毕;DOMContentLoaded 只代表 DOM 就绪,此时背景图、WebFont 还没来得及渲染,强行隐藏 loading 会造成 FOIT 或布局跳动。
- 必须用
window.addEventListener('load', () => { document.getElementById('loading').style.display = 'none'; }),不能写成window.onload = ...(后者会被后续赋值覆盖) - 建议加 8 秒超时兜底:
setTimeout(() => { ... }, 8000),防止某张图片 404 或 CDN 慢导致 loading 卡死 - 不要在
fetch或XHR里手动控制这个全局 loading——那是业务层 loading,和首屏 loading 是两回事
@keyframes spin + border-top-color 是最稳的旋转实现
直接给 border 加动画无效,因为 border 不是可动画属性;必须拆解为颜色变化或 transform。
立即学习“前端免费学习笔记(深入)”;
- 正确写法:
border: 4px solid #eee; border-top-color: #007bff;+@keyframes spin { to { transform: rotate(360deg); } } - 必须加
border-radius: 50%,否则是方块旋转 - Safari(尤其 iOS 15–16)需要硬件加速,加
transform: translateZ(0)或will-change: transform防止动画卡住 - 避免用
left/top位移做动画——性能差,且在 fixed 定位下易偏移
移动端 Safari 下 animation 停转?检查 transform 是否触发 GPU 加速
iOS Safari 对未启用硬件加速的 transform 动画有渲染降级策略,表现就是 spinner 转几圈后静止。
- 在动画元素上加
style="transform: translateZ(0);"或 CSS 中写transform: translateZ(0); will-change: transform; - 不要依赖
animation-play-state动态启停——Safari 对该属性支持不稳定 - 如果用 SVG
<circle></circle>+stroke-dashoffset,务必设transform-box: fill-box并确认 viewBox 尺寸匹配
最易被忽略的一点:loading 动画本身不该是“装饰”,而是页面资源加载链路里的一个可观测节点——它是否出现、何时消失,直接暴露了你的资源加载顺序、阻塞点和兼容性处理深度。



















