骨架屏动画必须用animation,因其需持续循环变化且无明确触发事件;transition依赖状态切换,无法满足占位元素在不可控加载时间内保持动态呼吸感的需求。

骨架屏动画该用 CSS 动画还是 transition?
直接用 animation,别碰 transition。骨架屏本质是“占位元素在加载中持续变化”,不是“从 A 状态切换到 B 状态”——transition 需要明确的起止值和触发时机,而图片懒加载完成时间不可控,强行用 transition 会导致脉冲中断、闪烁或完全不生效。
关键点在于:骨架元素(如 .skeleton-img)需始终处于动画中,直到真实图片 load 后被显式移除或隐藏。
- 用
@keyframes pulse定义从透明度 0.1 → 0.3 → 0.1 的循环变化,避免纯黑白闪动,更接近“呼吸感” - 动画时长设为
2.4s,比常见 1.5s 更舒缓,适配移动端弱网下用户等待预期 - 必须加
animation-fill-mode: forwards防止动画结束后回退到初始态(否则图片加载瞬间会跳变)
如何让骨架元素宽度/高度不塌陷又保持响应式?
懒加载图片未加载时,<img alt="移动端图片懒加载期间CSS如何生成精美的骨架屏脉冲动画?" > 自身宽高为 0,直接套骨架会导致父容器收缩、布局抖动。不能靠 JS 测量再写内联样式——移动端首屏渲染快,JS 执行滞后,骨架会“闪一下才撑开”。
正确做法是:用 aspect-ratio + min-height 双保险,且所有尺寸单位用 vh 或 rem,禁用 px。
立即学习“前端免费学习笔记(深入)”;
- 给骨架容器设
aspect-ratio: 16 / 9(按图实际比例),同时加min-height: 120px防 iOS Safari 旧版不支持aspect-ratio - 骨架色块用
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%),而非纯色,增强动态感 - 禁用
width: 100%,改用max-width: 100%+height: auto,避免横屏时拉伸失真
图片加载完成时如何平滑替换骨架而不闪动?
常见错误是直接 display: none 骨架或 opacity: 0,会导致重排或视觉跳跃。真实图片加载完成瞬间,其自然宽高可能与骨架容器不一致,尤其当用了 object-fit: cover 时。
必须等图片解码完成再切换,用 img.decode() + Promise 控制时序,而不是监听 load 事件。
-
img.addEventListener('load', () => { ... })只保证下载完成,不保证像素就绪;img.decode()才真正确保可绘制 - 替换逻辑应为:先给真实
<img alt="移动端图片懒加载期间CSS如何生成精美的骨架屏脉冲动画?" >设opacity: 0+position: absolute叠在骨架上 → 调用decode()→ 成功后设opacity: 1并移除骨架元素 - 务必加
will-change: opacity到真实图片上,避免 iOS Safari 动画卡顿
为什么 iOS Safari 上脉冲动画常卡顿或跳帧?
根本原因是 Safari 对 background-position 动画优化差,而很多骨架方案用它模拟流动光效。移动端 CPU 资源紧张,background-position 触发频繁重绘,iOS 尤其明显。
解决方案只有两个:换属性,或降级。
- 把光效动画从
background-position改成transform: translateX(),哪怕只是微小偏移(如translateX(-5px)),GPU 加速更稳 - 对 iOS Safari(
UA包含Version\/.*Safari)主动降级:动画时长延长至3.2s,关键帧减少为两段(0%→100%),降低帧率压力 - 绝不要在骨架元素上用
box-shadow或多层filter,iOS 渲染管线对此类属性极其敏感
骨架屏不是越 fancy 越好,脉冲节奏、色彩反差、容器稳定性,三者缺一都会让用户觉得“页面卡了”。最易被忽略的是 decode 时机和 iOS 的 transform 降级策略——这两处不处理,再美的 CSS 动画也白搭。


















