骨架屏必须服务端直出html,初始可见且占位布局;图片需预设宽高或aspect-ratio防抖动;ssr需服务端根据数据状态输出骨架或真实dom,结构一致避免hydration闪跳。

骨架屏必须和服务端 HTML 一起输出,不能靠 JS 插入
首屏白屏时间长,根本原因不是“没加载完”,而是浏览器在 DOMContentLoaded 前压根没东西可画。很多团队用 useState 或 v-if 控制骨架屏显隐,结果骨架等 JS 下载、解析、执行完才出现——这反而延长了用户第一眼看到内容的时间。
真正有效的做法是:服务端直出带骨架结构的 HTML,初始状态为可见、占位、参与布局流。比如卡片列表页,服务端返回的是:
<div class="card skeleton"> <div class="skeleton-image"></div> <div class="skeleton-title"></div> <div class="skeleton-text"></div> </div>
关键点:
- 所有骨架元素必须设
display: block(或与真实 DOM 一致),禁用visibility: hidden—— 它保留空间但不可见,JS 显示瞬间若样式未就绪,会闪出原始文字 - 真实内容加载后,用
opacity: 0 → 1切换,配合transition: opacity 0.3s ease,避免硬切 - SSR 场景下,客户端 hydration 前骨架已存在,hydration 后直接替换节点,不触发重排;若服务端没输出骨架,客户端 JS 才插入,就会闪一下
图片骨架屏必须预占尺寸,否则懒加载必抖动
图片加载抖动的根源从来不是动画慢,而是浏览器不知道它该占多大地方。只写 <img src="..."> 不设宽高,加载完成瞬间会把下方内容往下顶,CLS(累积布局偏移)直接爆表。
实操上分两种情况处理:
- 静态尺寸:直接在
<img>标签写width和height属性(不是 CSS),例如<img style="max-width:90%" style="max-width:90%">,现代浏览器据此推算 aspect-ratio,即使 CSS 覆盖也保布局稳定 - 动态/响应式尺寸:用
aspect-ratio: 16 / 9(Chrome 88+、Safari 15.4+),搭配width: 100%;旧版 Safari 降级为padding-top: 56.25%+position: relative容器 - 懒加载时,
IntersectionObserver的rootMargin至少设'100px',让图片在进入视口前就开始加载,避免滚动到才触发、用户看到白块
骨架容器必须匹配真实 DOM 的盒模型和字体度量
骨架看起来“对齐”不等于它真的没偏移。常见错觉是:两个 div 都设了 height: 24px,但一个用了 box-sizing: content-box,另一个是 border-box,真实文本行高又不同,最终换行位置、上下间距全错位。
必须统一的关键项:
- 所有骨架元素设
box-sizing: border-box - 文字类骨架用
line-height+font-size模拟,不用空格或min-height—— 例如真实段落line-height: 1.6,骨架也得用相同值 - 避免用
margin-bottom控制间距,改用gap(Flex/Grid)或padding-bottom,防止骨架和真实内容因 margin 折叠导致高度不一致 - 图片骨架容器加
display: block,否则<img>底部默认有空白间隙
服务端未输出骨架结构时,客户端 hydration 会闪跳
Vue/React 在 SSR 场景下,如果服务端返回的是真实内容,而客户端代码里又写了骨架逻辑(比如根据 loading 状态显示 skeleton),hydration 时会先渲染服务端内容,再被 JS 替换为骨架,最后才加载真实数据——用户看到的是「内容 → 灰色骨架 → 内容」三段式闪动。
解决路径很明确:
- 服务端模板中,当数据为空或未就绪时,输出骨架 HTML;数据就绪时,输出真实 HTML —— 两者结构必须完全一致(class 名、嵌套层级、key 值)
- 客户端组件里,不依赖
loading变量,而是检查data === null || data.length === 0;React 中初始 state 设为null,不是[] - 使用
keep-alive或页面缓存时,需监听activated(Vue)或useLayoutEffect(React),在用户重新进入页面时重置加载态,否则骨架逻辑失效
最易被忽略的一点:骨架屏不是“视觉糖”,它是首屏渲染链路上的基础设施。一旦结构不对齐、尺寸没预留、服务端没直出,所有 CSS 动画都救不了布局抖动和感知延迟。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











