骨架屏html结构必须与服务端返回的真实dom严格对齐,否则hydration错位导致“骨架闪一下再跳变”;需保证节点数量、class名、嵌套层级、兄弟顺序、动态逻辑(如v-if)完全一致,且骨架须直出首屏html而非运行时插入。

骨架屏 HTML 结构必须和服务端返回的真实 DOM 严格对齐
否则 hydration 会错位,用户看到“骨架闪一下、再跳成真实内容”的现象。这不是动画问题,是结构 mismatch 导致的 React/Vue 水合失败。
常见错误现象:document.querySelector('.card') 在服务端渲染出 3 个卡片,但骨架屏只写了 2 个 .skeleton-card;或者真实 DOM 中有 v-if="item.title" 动态控制的标题,骨架里却无条件渲染了 .skeleton-title。
- Vue 项目中,骨架结构需基于组件模板静态分析生成(如用
vue-template-compiler提取v-if/v-for节点),不能靠手写“大概像” - React 项目中,
react-loading-skeleton的<skeleton count="{data?.length"></skeleton>必须与真实列表长度一致,且初始data得是null或undefined,而非空数组[] - 所有骨架容器的 class 名、嵌套层级、兄弟节点顺序,都要和真实 DOM 完全一致——连注释位置都不建议改动(SSR 下部分框架会保留注释)
骨架屏不能靠 JavaScript 运行时插入,得在首屏 HTML 直出
如果骨架 DOM 是在 useEffect 或 mounted 钩子里用 innerHTML 或 appendChild 动态加进去的,那它一定晚于白屏出现,完全失去价值。
使用场景:首屏必须秒出骨架,尤其是 SSR 或静态生成(SSG)页面;移动端弱网下,JS 下载/执行可能延迟 1–2 秒,此时骨架还没渲染,用户就盯着白屏。
- 构建时注入:Webpack 插件(如
vue-skeleton-webpack-plugin)扫描路由组件,在 HTML 模板中直接写入对应骨架结构 - 服务端注入:Node.js 渲染层(如 Express + Vue SSR)根据当前路由匹配预编译好的骨架片段,拼进
index.html的<div id="app"> 内<li>禁止做法:不要在 <code>onMounted里调用document.getElementById('app').innerHTML = skeletonHTML;也不要依赖document.readyState === 'loading'做微延迟插入 - 推荐写法:
.skeleton-image { aspect-ratio: 16 / 9; },配合width: 100%自适应 - 兼容写法:
.skeleton-image { position: relative; } .skeleton-image::before { content: ''; display: block; padding-top: 56.25%; /* 16:9 */ } - 文字行高必须对齐真实内容:
line-height: 1.6和真实段落一致,禁用min-height或height控制文本占位,否则换行位置偏移 - 正确组合:
opacity: 0; pointer-events: none; transition: opacity 0.2s ease;→ 数据就绪后设opacity: 1; pointer-events: auto; - Vue 场景下,用
v-bind:style动态绑定,而不是v-show(它用display: none) - React 场景下,避免用
useState控制display或visibility,改用className切换 CSS 类
占位元素尺寸必须用 aspect-ratio 或 padding-top 百分比保比例
固定 height: 100px 的 .skeleton-image 在响应式布局下极易撑开或压缩,导致真实图片加载后页面“跳动”。这不是 CSS 动画问题,是盒模型失控。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
关键参数差异:aspect-ratio 是现代解法(Chrome 88+、Safari 15.4+),padding-top 百分比是兼容 fallback(需父容器 position: relative)。
显隐切换必须用 opacity + pointer-events,禁用 visibility:hidden
visibility: hidden 保留布局空间但不可交互,会导致骨架屏“看起来在、点不了”,且过渡生硬;更严重的是,它无法触发 CSS transition,动画卡顿。
性能影响:opacity 切换可被 GPU 加速,而 visibility 不参与合成层,动画帧率易掉;pointer-events: none 能避免骨架区域拦截点击,防止误触空白区触发事件。
真实项目里最常被忽略的,是骨架结构与真实 DOM 的“细微不一致”——比如一个 flex 容器里,真实内容用了 gap: 8px,骨架却用 margin-bottom: 8px;或者真实文本用了 font-size: 14px,骨架用了 16px。这些差之毫厘的偏差,会在 hydration 后造成肉眼可见的布局抖动。










