骨架dom树必须从原始html用domparser解析生成,保留class、style等布局属性,移除内容相关字段,内联css并确保class名与ssr一致,添加data-skeleton标记以便清理。

骨架 DOM 树不能靠手动写 HTML 或 CSS 拼凑,必须从原始结构中提取并重建——否则 SSR 水合失败、样式错乱、可访问性丢失是大概率事件。
DOMParser 是唯一安全的起点,别碰 document.body
很多人想直接操作当前页面的 document.body 来“生成骨架”,这会导致:样式污染、节点被意外修改、无法还原原始结构。真实工程中,骨架生成必须在隔离环境里做。
- 用
new DOMParser().parseFromString(htmlString, 'text/html')解析原始 HTML 或预处理后的 JSX 字符串,得到一个干净的Document对象 - JSX 必须先剥离动态表达式(如
{value}、onClick),只保留标签、class、style、width/height等布局相关属性,否则解析会失败或产出不可控节点 - 这个
Document就是你的“结构源”,后续所有遍历、替换、导出都基于它,和当前页面 DOM 完全无关
递归遍历时只保留 layout 属性,删掉一切 content 相关字段
骨架不是“加个灰色背景”,而是结构等价但语义清空。关键在于识别哪些属性影响布局、哪些纯属内容载体。
- 必须保留:
class(用于绑定骨架样式)、style(尤其是width、height、aspect-ratio、border-radius、display、flex相关声明) - 必须移除:
innerHTML、textContent、src、alt、value、data-*(除data-skeleton外)、aria-label(骨架无语义,不该提前注入) - 文本节点(
nodeType === 3)直接设为空或移除;<img>替换为带aspect-ratio的<div class="skeleton-img">;<code><button></button>替换为带圆角和固定宽高的灰色块导出前必须内联 CSS,且 class 命名要和服务端 hydration 对齐
生成的骨架 HTML 要能脱离构建环境直接部署,就不能依赖外部样式表或运行时 JS 注入。同时,class 名必须和 SSR 渲染结果完全一致,否则 React/Vue 会丢弃整个节点树重新挂载。
- 调用
documentElement.outerHTML获取骨架文档字符串,不要用body.innerHTML—— 会丢掉和内联样式 - 把骨架所需 CSS(含
@keyframes animate-pulse、CSS 变量定义)写死进<style></style>标签,并插入到中 - 禁止使用动态拼接 class,比如
class="card ${loading ? 'skeleton' : ''}";服务端永远输出class="card skeleton-card",客户端 hydrate 时也必须渲染同名结构 - 所有骨架节点加上
data-skeleton="true",方便加载完成后用document.querySelectorAll('[data-skeleton]')精准清理,避免残留
真正难的不是“怎么画灰色块”,而是让骨架结构在 SSR/CSR 切换、CSS 加载顺序、字体未就绪、无障碍读屏等边界条件下依然稳定。这些细节不写进构建流程,光靠手写或截图生成,迟早会在某个上线凌晨三点崩给你看。
- 调用











