如何筛选网页中包含可见文本的HTML节点
筛选页面实际渲染可见文本节点的实现方案
核心判定逻辑
要排除非实际渲染的文本节点,只需要从渲染根节点出发遍历,过滤掉所有不满足可见条件的节点即可,不需要额外限制视口位置:
- 直接从
document.body开始遍历,天然跳过<head>内的<title>、<meta>、<script>等默认不在页面渲染的标签 - 过滤CSS属性导致不可见的元素:
display: none、visibility: hidden、opacity: 0、宽高为0且overflow: hidden的元素及其子节点 - 跳过纯空白、无实际文本内容的文本节点
可直接运行的实现代码
使用TreeWalker遍历文本节点的效率远高于全量DOM遍历,适合在Chrome扩展中使用:
/** * 获取页面所有实际渲染的可见文本节点 * @returns {Text[]} 可见文本节点集合 */ function getVisibleTextNodes() { const visibleNodes = []; const excludeTags = new Set(['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEMPLATE']); const walker = document.createTreeWalker( document.body, NodeFilter.SHOW_TEXT, { acceptNode(node) { // 跳过无实际内容的空白文本 if (!node.textContent.trim()) return NodeFilter.FILTER_REJECT; const parent = node.parentElement; if (!parent || excludeTags.has(parent.tagName)) return NodeFilter.FILTER_REJECT; const style = window.getComputedStyle(parent); const rect = parent.getBoundingClientRect(); // 判定不可见场景 if ( style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0 || (rect.width === 0 && rect.height === 0 && style.overflow === 'hidden') ) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } } ); let node; while (node = walker.nextNode()) { visibleNodes.push(node); } return visibleNodes; }
提取实际使用字体的逻辑:
// 聚合所有可见文本使用的字体 const usedFontSet = new Set(); getVisibleTextNodes().forEach(textNode => { const font = window.getComputedStyle(textNode.parentElement).fontFamily; usedFontSet.add(font); }); // 最终结果:所有实际被可见文本使用的字体 const allUsedFonts = Array.from(usedFontSet);
补充说明
- 该方案不会限制节点必须在当前视口内,页面任意滚动位置的可见元素都会被识别
- 如果需要统计伪元素(
::before/::after)通过content属性渲染的文本,可以额外遍历所有DOM节点,获取伪元素的计算样式补充到结果中 - 如果需要覆盖
transform: scale(0)、clip-path裁剪隐藏等特殊隐藏场景,可以在判定规则中补充对应的检测逻辑,比如检测元素getBoundingClientRect()返回的宽高是否为0即可覆盖大部分缩放隐藏的场景
内容的提问来源于stack exchange,提问作者bugsyb
相关产品推荐
相关产品推荐

