加载动画必须置于<body>开头,用fixed定位和高z-index确保覆盖,配合window.onload+8秒超时隐藏,辅以body opacity过渡和font加载判断,避免闪屏与卡顿。

加载动画必须写在 <body> 开头,不是结尾
很多人把 loading 遮罩层放在 </body> 前面,结果页面闪一下才出现动画——因为浏览器是自上而下解析 HTML 的,遮罩层晚渲染,就失去了“加载中”的意义。
正确做法是:在 <body> 标签后立刻插入 loading 元素,并用内联 CSS 固定定位:
<body>
<div id="loading" style="position:fixed;top:0;left:0;width:100vw;height:100vh;background:#fff;z-index:9999;display:flex;justify-content:center;align-items:center;">
<div style="width:40px;height:40px;border:3px solid #eee;border-top-color:#007bff;border-radius:50%;animation:spin 1s linear infinite;"></div>
</div>
<!-- 其他内容 -->-
position: fixed和z-index: 9999缺一不可,否则会被内容顶开或压在底层 - 不要用
visibility: hidden或display: none初始化遮罩层——它得一开始就显示 - 动画用纯 CSS(如
@keyframes spin),避免 JS 未加载时空白
window.addEventListener('load', ...) 才是隐藏 loading 的正确时机
DOMContentLoaded 太早:图片、字体、外部 CSS 还没加载完,用户可能看到内容“闪入”,而 loading 还没消失;window.onload 正好等全部资源就绪,包括 <img>、<link rel="stylesheet">、<script>。
但要注意兜底:如果某张图 404 或 CDN 挂了,load 可能永远不触发。所以加个 8 秒超时:
立即学习“前端免费学习笔记(深入)”;
const hideLoading = () => {
const el = document.getElementById('loading');
if (el) el.style.display = 'none';
};
window.addEventListener('load', hideLoading);
setTimeout(hideLoading, 8000);- 别用
document.body.removeChild(...),直接display: none更安全,避免 DOM 操作失败报错 - 移动端 Safari 对
transform动画有时卡顿,优先用border+animation: spin这类兼容性更好的方案 - 如果用了 Web Font,确保字体加载完成再隐藏 loading —— 可配合
document.fonts.load()补充判断
防止 FOUC(无样式闪烁)的同时保留 loading 动画
外部 CSS 加载慢时,HTML 会先以无样式状态渲染,loading 层可能一闪而过甚至看不见。解决方案不是阻止渲染,而是控制可见性节奏。
在 <head> 内联一段 CSS:
<style>
body { opacity: 0; transition: opacity 0.3s ease; }
body.loaded { opacity: 1; }
</style>然后在 window.addEventListener('load', ...) 里同时操作:
document.body.classList.add('loaded');
document.getElementById('loading').style.display = 'none';- 不能只靠
opacity控制 body,否则 loading 层也会被透明化(因层级关系)——它必须是fixed且z-index足够高 - 不用
visibility: hidden替代,它不触发重排,但会破坏 loading 层的渲染上下文 - 这个组合对 iOS Safari 15–16 特别有效,能绕过其对
transform动画的渲染 bug
渐变背景类 loading 动画要配 background-size: 400% 400%
只写 background: linear-gradient(...) + animation: gradientShift 是不够的。没有放大背景尺寸,background-position 动画只会原地抖动,看不出流动感。
关键参数必须齐备:
.loading-bg {
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
background: linear-gradient(-45deg, #ff6b6b, #4ecdc4, #44b5f2, #9b59b6);
background-size: 400% 400%; /* 必须设为 200% 以上 */
animation: gradientShift 6s ease-in-out infinite;
z-index: -1;
}-
background-size: 400% 400%是让渐变色块足够大,才能通过background-position移动产生平滑过渡 - 动画时长建议 1.2s–1.8s 用于首屏遮罩;如果是全屏背景循环动画,6s 更自然
- 结束时若需锁定终态(比如切换为真实背景),加
animation-fill-mode: forwards并用 JS 在load后移除该元素
真正难的不是写出动画,而是判断它该在哪个时刻出现、又该在哪个确切帧消失——timing 错 100ms,体验就从“丝滑”变成“卡顿”。



















