我在排查白屏问题时,最容易犯的错误就是一上来就打开 Network 面板逐个请求看状态码。实际上,白屏的根因多数不在某个资源 404,而在于路由解析与资源加载顺序之间的时序错位。这篇文章把我常用的定位方法整理成一条可复用的排查路径。
白屏的本质是什么?
结论: 白屏不是"页面没加载出来",而是"HTML 已经返回、CSS 已经解析,但 JavaScript 还没有把根节点渲染出来,或者渲染过程中抛错中断"。定位白屏的核心,是搞清楚在哪个时间点、哪个资源、哪一步逻辑断了。
Google 的公开数据显示,页面加载时间从 1 秒增加到 3 秒,跳出率会增加 32%;从 1 秒增加到 5 秒,跳出率上升 90%(来源:Google/SOASTA 移动端性能研究,2017 年公开报告)。Deloitte 与 Google 联合分析了 37 个品牌站点、超过 3000 万次会话后发现,移动端加载速度每提升 100 毫秒,零售转化率平均提升 8.4%,平均订单价值提升 9.2%(来源:Deloitte Digital《Milliseconds Make Millions》研究报告)。这意味着白屏不仅是技术问题,直接影响商业结果。
第一步:按路由锁定问题范围
白屏往往不是全站问题,而是特定路由下才出现。我会先做三件事:
- **复现路由:**确认是 `/order/detail` 这种动态路由,还是 `/about` 这种静态路由。
- **对比兄弟路由:**同一个父路由下,其他子路由是否正常?如果兄弟路由正常,问题大概率在该路由对应的组件懒加载 chunk。
- **检查路由守卫:**前端框架(React Router / Vue Router)的 beforeEach 或 loader 中,是否有未 catch 的 Promise rejection 导致路由跳转中断。
路由层常见断点
| 断点位置 | 典型现象 | 排查方法 |
|---|---|---|
| 路由守卫 | URL 变了但页面不渲染 | 在守卫函数首尾打 log,看是否走到 next() |
| 异步组件 loader | 控制台报 chunk load failed | 检查 CDN 是否挂了、chunk 文件名是否带 hash 与部署版本不一致 |
| 路由参数解析 | 特定 ID 白屏,其他 ID 正常 | 打印 useParams / $route.params,看是否拿到了 undefined |
第二步:按资源加载顺序还原时间线
白屏定位最有效的工具不是肉眼盯 Network,而是Performance 面板的火焰图。我会按这个时间顺序逐个检查:
T+0ms
HTML 文档返回
检查 Document 请求是否 200,TTFB 是否正常。如果 HTML 本身慢,后面都白搭。
T+~100ms
关键 CSS 解析
CSSOM 构建是否被阻塞?有没有@import 嵌套导致串行请求?
T+~300ms
主 JS chunk 下载与执行
这是白屏高发区。检查 chunk 是否被 defer/async 正确标记,执行时长是否超过 3 秒。
T+~500ms
框架初始化(createApp / ReactDOM.render)
这里抛错会直接导致根节点为空。看 Console 是否有 Uncaught Error。
T+~800ms
路由组件挂载、首屏数据请求
组件内 useEffect / onMounted 里的数据请求如果抛错且未捕获,会导致渲染中断。
一段我常用的根节点兜底代码
// 在入口处增加全局错误捕获,避免白屏无声
window.addEventListener('error', (event) => {
console.error('[WhiteScreenGuard] 捕获到未处理错误:', event.error);
// 上报到监控平台
reportError({
message: event.message,
filename: event.filename,
lineno: event.lineno,
href: location.href
});
});
// Promise 拒绝也要抓
window.addEventListener('unhandledrejection', (event) => {
console.error('[WhiteScreenGuard] 未处理的 Promise:', event.reason);
});
第三步:区分"真白屏"和"假白屏"
这是我踩过最多的坑。
现象: 用户反馈白屏,但我远程打开 DevTools 看,页面明明渲染出来了。
根因: 这不是真白屏,而是骨架屏(Skeleton)停留时间过长,用户以为页面卡住了。我之前在一个订单列表页把 loading 组件做成了和背景同色,导致"看起来是白屏",实际 DOM 已经有内容。
排查证据: 用 Performance 面板看 First Contentful Paint,如果 FCP 时间正常但用户说白屏,去检查骨架屏的颜色和展示时长。
**修复方式:**骨架屏使用明确的灰色块 + 呼吸动画,让用户感知到"正在加载"。
资源加载顺序的三个工程优化
定位之后,我通常会顺手做这三件事:
- **关键 CSS 内联:**首屏 above-the-fold 的 CSS 直接内联到 HTML,避免外部 CSS 文件阻塞渲染树构建。
- **路由级代码分割:**用 React.lazy / defineAsyncComponent 把非首屏路由的 chunk 拆出去,保证首屏 chunk 体积可控。
- 资源预加载: 对首屏必须的 JS 加
<link rel="preload">,对可能跳转的下一路由加<link rel="prefetch">。
白屏率的量化监控
最后一步是把这个问题从"被动排查"变成"主动监控"。白屏率的计算公式我一般这样定义:
白屏率 = 根节点子元素数量为 0 的会话数 / 总会话数
具体实现上,在页面 load 事件后延迟 3 秒检查一次 document.getElementById('app').childElementCount,如果为 0 就上报一条白屏事件。这个指标配合路由维度下钻,就能快速发现是哪条路由的问题。
写在最后:排查路径的核心
**结论:**白屏定位按"路由范围 → 时间线断点 → 真假白屏"三步走,比逐个请求看状态码高效得多。核心是建立对资源加载顺序的时序感,知道每一阶段浏览器在做什么、哪一步最容易断。
FAQ
Q1:白屏但控制台没有任何报错,怎么查?
A:优先用 Performance 面板看 FCP 之后是否有长任务(Long Task)阻塞主线程。没有报错但页面不渲染,往往是 JS 死循环或某个同步任务卡住了渲染。
Q2:只在生产环境白屏,本地正常?
A:大概率是 chunk hash 与 CDN 缓存不一致。检查 index.html 引用的 JS 文件名是否和 CDN 上实际存在的文件匹配,给 HTML 加 no-cache 头。
Q3:白屏率多少算正常?
A:没有统一的行业标准。我所在团队的内部阈值是:白屏率超过 1% 需要关注,超过 3% 需要立即排查。不同体量的站点基线不同,建议自己积累一个月数据后设定内部告警线。
Q4:SSR 页面也会白屏吗?
A:会。SSR 白屏通常是服务端渲染过程中抛错,降级到客户端渲染(CSR)时 hydrate 失败。看服务端日志和浏览器端报错是否对得上。
参考资料
- Google/SOASTA. Mobile Page Speed and Conversion Rate. 2017.
- Deloitte Digital. Milliseconds Make Millions. 2018.
- Web.dev. Web Vitals 指标定义与测量指南.