骨架结构必须复用真实dom层级和类名,确保嵌套深度、容器类、宽高声明一致以避免重排;动画仅用linear-gradient位移,首屏骨架内联,切换通过css逻辑原子化控制。

骨架结构必须复用真实DOM层级和类名
骨架屏不是画个“看起来像”的草图,而是要让浏览器在加载真实内容前,先渲染出一个布局完全一致的占位结构。一旦骨架和真实内容的
常见错误现象:.skeleton-card里只有一层
.card内部有.card-inner → 加载后卡片高度突变;用height: 100%撑开骨架图片容器 → 父元素没高度时骨架直接坍缩消失。
- 真实组件用
.product-grid+grid-cols-4,骨架就照抄,别另起.skeleton-grid - 商品卡片中图片区域是
<div class="product-image aspect-square"></div>,骨架就用相同结构+aspect-ratio,不用img标签 - 文字行数必须一一对应:标题1行 → 1个
.skeleton-text-title;摘要3行 → 3个独立.skeleton-text,不用伪元素控制行高
动画只用linear-gradient + background-position
移动端尤其iOS Safari对transform动画支持不稳定,opacity淡入淡出会触发重绘层提升,增加GPU负担。最轻量、兼容性最好的方案是纯CSS渐变位移动画。
关键点在于方向与内容流匹配:首页横向滚动Banner用to right,垂直列表商品项用to bottom;且必须加will-change: background-position,否则Chrome某些版本会出现闪烁。
- 示例代码中
@keyframes loading只改background-position,不动background-size或颜色值 - 暗色模式下避免用
#f0f0f0这类硬编码灰度,改用color-scheme: light限定或CSS变量 - 动画时长设为
1.5s而非2s以上——用户感知阈值约1.2~1.8s,过长反而显得卡顿
首屏骨架必须内联,非首屏按需注入
电商首页首屏内容(Banner、导航栏、热销榜)决定用户第一印象,骨架必须随HTML一起下发,不能等JS执行后再插入。否则白屏时间会叠加网络延迟+JS解析+DOM操作三段耗时。
非首屏模块(如“猜你喜欢”、“店铺推荐”)可延迟注入,但得靠IntersectionObserver监听进入视口再渲染骨架,而不是等数据请求返回才开始。
- 首屏骨架HTML写在
开头,CSS内联在里,确保无阻塞渲染 - 非首屏骨架模板存为
template标签或JS字符串,用document.createElement动态挂载,避免提前占用内存 - 服务端渲染(SSR)场景下,
data-loading="true"应由服务端注入根节点,JS只负责移除,不负责初始显隐判断
骨架与真实内容切换必须原子化
“先显示骨架 → 请求数据 → 隐藏骨架 → 显示内容”这个流程极易出现闪屏:骨架刚渲染完,JS还没来得及display: none,真实内容就已插入并触发重绘,造成视觉撕裂。
正确做法是把骨架和真实内容放在同一DOM位置,用CSS逻辑控制显隐,而非JS反复操作style.display。
- 结构上写成:
<div class="section"> <div class="skeleton">...</div> <div class="content">...</div> </div> - CSS写成:
[data-loading="true"] .content { display: none; }+[data-loading="true"] .skeleton { display: block; } - JS只做一件事:数据就绪后
document.documentElement.removeAttribute('data-loading'),其余全由CSS接管
最易被忽略的是:骨架的width/height必须精确到像素或aspect-ratio,不能依赖内容撑开;否则切换瞬间仍会因尺寸计算差异引发微小偏移——人眼虽不易察觉,但对转化率有真实影响。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











