白屏监控怎么判断页面真的白屏了?

Tr° 熙然 阅读 7

我在做前端白屏监控,现在用的是检测 body 是否有子元素的方法,但发现有些情况误报特别多。比如页面加载中还没渲染完,或者骨架屏占位的时候也被当成白屏了,这咋办?

我试过加个延时再检测,但时间不好控制,网络慢的时候还是会误判。有没有更靠谱的判断方式?比如结合 DOM 节点数量和可见内容?

目前代码大概是这样:

function isBlankScreen() {
  const elements = document.body.children;
  return elements.length === 0 || (elements.length === 1 && !elements[0].innerHTML.trim());
}
我来解答 赞 5 收藏
二维码
手机扫码查看
1 条解答
一诺
一诺 Lv1
白屏监控这事儿我踩过不少坑,光靠判断 body 有没有子元素确实太粗暴了,骨架屏、加载中、甚至一个空 div 都能被误伤。

关键得搞清楚:什么是“用户视角下的白屏”?
不是 DOM 有没有,而是“用户眼前有没有实际内容”。

我现在的做法是分三层判断,基本能避开 99% 的误报:

第一层,先等页面到「内容可读」阶段,别一上来就查。
可以用 document.readyState === 'complete' 或者监听 load 事件,或者更激进点——等 PerformanceObserver 里拿到 first-contentful-paint(FCP)时间,再开始监控。
没这一步,你永远在跟加载中的页面打架。

第二层,别只看 DOM 数量,看可见内容节点。
比如:
- body 里是不是有文本节点(不是空格那种)
- 有没有图片、svg、canvas、video、iframe 这类自带内容的元素
- 有没有真正的语义标签(比如 <p><h1><article>)带内容

简单点的实现可以这样:

function hasVisibleContent() {
const body = document.body;
if (!body) return false;

const children = body.children;
if (children.length === 0) return false;

let hasContent = false;

for (let el of children) {
// 跳过那些明显是占位/骨架屏的常见类名(自己按项目加)
if (el.classList.contains('skeleton') ||
el.classList.contains('loading-placeholder')) {
continue;
}

// 有文本内容(去掉空白后非空)
if (el.textContent && el.textContent.trim().length > 0) {
hasContent = true;
break;
}

// 有图片、svg、canvas 这类内容型元素
if (el.tagName === 'IMG' ||
el.tagName === 'SVG' ||
el.tagName === 'CANVAS' ||
el.tagName === 'VIDEO' ||
el.tagName === 'IFRAME') {
hasContent = true;
break;
}

// 递归查子元素(避免单层 div 包裹太深)
if (el.children.length > 0 && hasVisibleContentInTree(el)) {
hasContent = true;
break;
}
}

return hasContent;
}

function hasVisibleContentInTree(node) {
if (node.nodeType === Node.TEXT_NODE && node.textContent.trim().length > 0) {
return true;
}
if (node.children.length === 0) return false;
for (let child of node.children) {
if (hasVisibleContentInTree(child)) return true;
}
return false;
}


第三层,加个“内容尺寸”兜底。
白屏通常意味着页面可视区域没东西,哪怕 DOM 有,但可能被隐藏了(display:none、opacity:0、宽高为 0)。
可以测下 body 或某个主容器的 offsetWidthoffsetHeight,如果小于一个阈值(比如 100px),再结合上面的判断。

另外,骨架屏场景可以主动加个 class,比如 class="skeleton-active",监控时主动跳过这类阶段。
或者用 data-skeleton="true" 这种更可控的方式。

最后提醒一句:
别在页面刚 load 完就马上下结论,建议加个 200~500ms 的 debounce,避免首屏渲染还没完你就报错,那不是监控,是添乱。

CSS的话,有些骨架屏是用 background: linear-gradient 模拟的,这种 DOM 看着有内容,但实际没文本——这种情况只能靠自己约定 class 或 data 属性来排除,纯技术手段很难 100% 搞定。
点赞 1
2026-02-27 10:01