background-position动画是唯一靠谱方案,因其只改变渐变绘制起点,不触发重排重绘,GPU加速且像素精准;需用两层linear-gradient分离结构与光效、固定像素background-size、to right方向、linear缓动及伪元素覆盖,并加载完成立即display: none。

直接用 animate-pulse 或纯 background-color 永远做不出逼真骨架屏——它缺乏结构感、会跳动、在 iOS 上卡顿,且加载完成时容易闪一下。
为什么 background-position 动画才是唯一靠谱方案
opacity 动画只是忽明忽暗,transform 移动在 Safari 和安卓 WebView 里边缘发虚、锯齿明显;而 background-position 只改变渐变绘制起点,不触发重排重绘,GPU 合成层加速,像素对齐精准。
- 渐变方向必须是
90deg或to right,否则光效反向,违反阅读流 -
background-size宽度必须大于容器(如200px 100%或200% 100%),否则位移一到边界就断掉 - 关键帧中单位不能省:
background-position: -200px 0,不能写成-200 0(IE/旧 Chrome 会忽略) - 缓动必须用
linear,ease会让光在两端滞留,破坏流动感
两层 linear-gradient 必须分开写,且参数强耦合
单层渐变只能铺灰,看不出标题、头像、段落的层次。必须用 background-image 显式声明两层:底层画结构,上层扫光,且共用同一组 background-size 和 background-position,否则光条漂移、动画错位。
- 底层结构示例:
linear-gradient(to right, #f0f0f0 0%, #e0e0e0 50%, #f0f0f0 100%) - 上层扫光示例:
linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.3) 50%, rgba(255,255,255,0) 100%) - 必须加
background-repeat: no-repeat,否则重复导致闪烁跳变 - iOS Safari 不支持
rem、vw作为background-size单位,写等于没写——固定像素最稳
伪元素覆盖 + overflow: hidden 是防错位底线
动画不能直接绑在骨架容器上,否则内容加载后动画还在跑,多个节点还可能复用动画实例导致节奏混乱。真正生效的,是每个骨架子元素的 ::before 伪类。
立即学习“前端免费学习笔记(深入)”;
- 父容器必须设
position: relative,伪元素才不会脱标 -
::before必须带content: ""和position: absolute - 所有骨架容器必须加
overflow: hidden,否则圆角区域光效滑出会漏白边 - 图片占位优先用
aspect-ratio: 4/3+width: 100%,别写死height,小屏缩放才不畸变
加载完成瞬间必须 display: none,不是等动画结束
骨架层 DOM 节点如果靠 JS 删除或只切 opacity,真实内容插入时会触发重排,页面“跳一下”;若等动画播完再隐藏,又会出现“闪一下”感。
- 正确做法:JS 获取数据后立即给骨架容器加
is-loaded类,CSS 中写.skeleton.is-loaded { display: none; } - 服务端 HTML 必须包含骨架结构,且初始可见——不能靠 JS 插入,否则 LCP 直接恶化
- Vue/React 中避免只用
v-if或三元渲染切换,推荐v-show+key强制重置状态 - SSR 场景下,骨架屏不能出现在首屏 HTML 中,需用
typeof window !== 'undefined'做客户端水合判断
最易被忽略的是:移动端 background-size 单位失效、伪元素未设 content 导致不渲染、以及加载完成时没立刻 display: none ——这三点一出,骨架屏就从体验优化变成体验破绽。


















