目标
转圈承诺不了任何东西,于是内容到达时重排页面,等待感远超网络时延。复制真实布局的骨架屏是内容会兑现的承诺:到达零位移、各区域独立落位、感知等待因没有跳变而缩短。全部要义在于“先测量再模仿”,外加把假进度条换成诚实的阶段播报。
步骤要点
- 加载完成后在控制台量出真实几何:卡片数、卡片高度、图片宽高比、标题行数,作为骨架的唯一依据。
- 骨架按测得尺寸用 grid 模板行构建,图片行用 aspect-ratio,微光动画走背景渐变并尊重 prefers-reduced-motion。
- 用 Suspense 分区渐进揭示:外壳立即出,Header、Stats、Activity 各配各的骨架,快区域不等慢区域,交接只发生在自己那块。
- 删掉爬到 90% 就卡住的假进度条,换成绑定真实里程碑的分段状态行,role=status 加 aria-live 让读屏器同步听见。
- 复测双指标:CLS 从 0.18 降到 0.01,且内容落位时页面不再跳。
排错提示
骨架几何跨断点错位是因为硬编码高度只对一个视口成立,改用与真实卡片同一套 grid 与 token,让 aspect-ratio 行自然计算;微光在低端机卡顿是 background-position 动画持续重绘,换 transform translateX 伪元素、节制 will-change、并尊重减少动效偏好冻结;加载快于一百毫秒时骨架会闪一下灰,加 150-300ms 延迟阈值,瞬时内容永远优于教会用户“这应用会闪”。
适用边界
骨架模仿形状不模仿内容,未知长度列表没有代表性估计就做不出诚实的骨架;感知提速依赖几何匹配,错误的骨架只是把跳变换成错位,用户照样觉得糙。
代码示例
spinner version:
t=0ms centered spinner (layout: empty)
t=1.9s content arrives, layout JUMPS down 620px
CLS 0.18, "feels slow", scroll position lost
skeleton version (measured geometry):
t=120ms 12 card skeletons, 214px, 16:9 image rows
t=0.9s header region settles (its own Suspense)
t=1.9s activity region settles (its own Suspense)
CLS 0.01, zero jump, regions fade in place