
本文介绍一种适用于纯静态 HTML 页面的实用方案:通过手动统计关键资源数量并监听其 onload 事件,动态计算并渲染百分比进度条,兼顾准确性与兼容性,无需服务端支持或复杂 API。
本文介绍一种适用于纯静态 html 页面的实用方案:通过手动统计关键资源数量并监听其 `onload` 事件,动态计算并渲染百分比进度条,兼顾准确性与兼容性,无需服务端支持或复杂 api。
在静态网站中实现真实、可感知的加载进度条(而非纯动画“假进度”),核心难点在于浏览器原生不提供页面总资源体积和已传输字节数的公开接口(如 XMLHttpRequest 的 progress 事件仅适用于主动发起的请求,无法监控 、、<script> 等标签的加载过程)。因此,<strong>基于资源加载完成计数的模拟方案成为最可靠、兼容性最佳的选择。</script>
该方案不依赖 PerformanceObserver 或 Resource Timing API(后者需开启 CORS 且部分资源可能被过滤),也不使用不可靠的 document.readyState 或 window.onload(它们只提供“完成”信号,无中间进度)。而是采用显式声明 + 事件驱动的方式:
-
预估关键资源总数:手动统计 HTML 中需等待的外部资源,包括
、<script>、<link rel="stylesheet"> 等;</script>
- 为每个资源绑定 onload(及 onerror)回调:确保资源成功加载或失败时均计入进度;
- 实时更新进度条:用已加载数 ÷ 总数 × 100 计算百分比,并同步更新 UI;
- 设置安全兜底机制:防止因资源加载失败或遗漏导致进度卡死。
以下是一个完整、可直接运行的示例:
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>静态页加载进度条</title><style>
.loading-overlay {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 9999;
transition: opacity 0.3s ease;
}
.progress-bar {
width: 300px;
height: 6px;
background: #e0e0e0;
border-radius: 3px;
overflow: hidden;
margin-bottom: 16px;
}
.progress-fill {
height: 100%;
background: #4CAF50;
width: 0%;
transition: width 0.2s linear;
}
.progress-text {
font-size: 18px;
color: #333;
font-weight: 500;
}
main { display: none; }
</style><!-- 加载遮罩层 --><div class="loading-overlay" id="loadingOverlay">
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="progress-text" id="progressText">0%</div>
</div>
<!-- 主要内容(初始隐藏) -->
<main id="mainContent"><h1>欢迎来到我的静态网站</h1>
<p>所有资源加载完成后才显示此内容。</p>
<img src="https://placekitten.com/400/200?x-oss-process=image/resize,p_40" alt="示例图1" onload="onResourceLoad()" onerror="onResourceLoad()"><img src="https://placekitten.com/400/200?x-oss-process=image/resize,p_40" alt="示例图2" onload="onResourceLoad()" onerror="onResourceLoad()"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" onload="onResourceLoad()" onerror="onResourceLoad()">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" onload="onResourceLoad()" onerror="onResourceLoad()"></script></main><script>
// 配置:手动设定预期加载的资源总数(含 img/link/script)
const TOTAL_RESOURCES = 4; // 注意:此处需与实际资源数量严格一致
let loadedCount = 0;
function onResourceLoad() {
loadedCount++;
const progress = Math.min(100, Math.round((loadedCount / TOTAL_RESOURCES) * 100));
document.getElementById('progressFill').style.width = `${progress}%`;
document.getElementById('progressText').textContent = `${progress}%`;
if (progress >= 100) {
// 完全加载后,渐隐遮罩、显示主内容
setTimeout(() => {
document.getElementById('loadingOverlay').style.opacity = '0';
setTimeout(() => {
document.getElementById('loadingOverlay').style.display = 'none';
document.getElementById('mainContent').style.display = 'block';
}, 300);
}, 200);
}
}
// 兜底超时机制:3秒后强制展示(防异常阻塞)
setTimeout(() => {
if (loadedCount < TOTAL_RESOURCES) {
console.warn(`加载超时,${TOTAL_RESOURCES - loadedCount} 个资源未就绪,强制完成`);
document.getElementById('progressFill').style.width = '100%';
document.getElementById('progressText').textContent = '100%';
setTimeout(() => {
document.getElementById('loadingOverlay').style.opacity = '0';
setTimeout(() => {
document.getElementById('loadingOverlay').style.display = 'none';
document.getElementById('mainContent').style.display = 'block';
}, 300);
}, 200);
}
}, 3000);
</script>
✅ 关键注意事项:
- 总数必须准确:TOTAL_RESOURCES 值需与 HTML 中显式添加 onload/onerror 的资源标签数量完全一致,否则进度将失真;
- 务必包含 onerror 处理:网络失败或资源 404 时也应计入加载完成,避免进度卡死;
- CSS/JS 文件需内联 onload 属性: 和 <script> 标签不支持 onload 作为属性(HTML 规范限制),但现代浏览器普遍支持,实测兼容 Chrome/Firefox/Safari/Edge;若需极致兼容,可改用 addEventListener('load', ...) 动态绑定;</script>
-
不适用于动态插入资源:该方案仅覆盖初始 HTML 中声明的资源,后续 JS 动态创建的
等需额外管理;
- 移动端友好:代码无依赖、轻量,适合所有静态站点,尤其适合 Jekyll、Hugo、VuePress 等生成的静态页面。
这种方案虽非“真实字节级进度”,但在用户体验层面高度可信——它真实反映了用户可见内容(图片、样式、交互脚本)的就绪状态,比单纯播放动画更符合“加载完成即可用”的直觉逻辑。










