用 aspect-ratio + background 实现固定比例占位与骨架动画:aspect-ratio: 16/9 撑开空间防抖动,老 safari 回退 padding-top;骨架用 linear-gradient 背景动画模拟光扫效果;img 加载完成通过 opacity 过渡平滑替换,伪元素骨架需在 is-loaded 下隐藏。

用 aspect-ratio + background 实现固定比例占位
图片懒加载前必须撑开空间,否则页面会“抖动”。不用 JS 计算宽高,纯 CSS 就能锁定比例:aspect-ratio 是最直接的解法,兼容性已覆盖 Chrome 88+、Firefox 89+、Safari 15.4+。老版本 Safari 需 fallback 到 padding-top 百分比技巧。
- 推荐写法:
aspect-ratio: 16 / 9(比用width: 100%; padding-top: 56.25%更语义、更可控) - 若需兼容 iOS 15.0–15.3,加一层伪元素或内联
padding-top,但注意:padding-top基于父容器宽度,父容器必须有明确width - 不要用
height: 0+padding-top后再绝对定位图片——这会让骨架层脱离文档流,影响可访问性和 SEO
灰色脉冲动画用 @keyframes + background 渐变实现
骨架动画本质是背景色流动感,不是真图片闪烁。用 linear-gradient 模拟“光扫过”的效果,比 GIF 或多层遮罩更轻量、更易控速。
- 关键点:用
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)配合background-size: 200% 100%,再用animation平移背景位置 - 动画时长建议设为
2s,太快显得躁,太慢失去“加载中”暗示;animation-timing-function: ease比linear更自然 - 别给骨架层加
opacity动画——它和背景动画叠加后容易糊成一片灰,用户看不出“脉冲”
img 加载完成时如何平滑替换骨架
图片加载完成瞬间直接显示,会生硬跳变。要用 CSS 过渡接管这个切换过程,而不是等 JS 插入 class 再触发。
- 给
img设置opacity: 0; transition: opacity 0.3s ease,初始隐藏 - 监听
img.onload后加一个 class(如is-loaded),该 class 仅含opacity: 1—— 这样过渡由浏览器原生触发,不依赖 JS 动画帧 - 别用
visibility: hidden → visible切换:它不触发动画,且visibility不参与合成层,可能造成重排 - 如果骨架层是
::before伪元素,记得在img.is-loaded下用&::before { display: none }关掉它,避免叠在图片上
响应式下骨架比例错乱的常见原因
骨架在小屏突然变扁或拉伸,往往不是代码写错,而是布局上下文被干扰。
立即学习“前端免费学习笔记(深入)”;
- 检查父容器是否用了
flex且没设align-items: stretch—— flex 子项默认不拉伸,aspect-ratio会失效 - 如果图片在外层
grid容器里,确认没设grid-template-columns: minmax(0, 1fr))这类强制收缩规则,它会压扁子项的aspect-ratio - 用
object-fit: cover的图片本身不影响骨架,但若骨架层用了background-size: cover,就和图片行为耦合了——骨架层只该用background-size: 100% 100%或渐变平铺
真正难调的不是动画或比例,而是骨架层和真实图片在不同 layout context 下的尺寸博弈。比如 aspect-ratio 在 inline-flex 容器里会被忽略,这种细节查起来费时间,但改一行 display 就好。










