::before 适合做图片占位加载效果,因其是不触发请求、不影响语义的伪元素,可预留空间、叠加骨架动画,配合 aspect-ratio 或 padding-top 实现无抖动占位,加载完成通过 class 切换隐藏。

为什么 ::before 适合做图片占位加载效果
因为 ::before 是伪元素,不参与 DOM 渲染流程,不会触发图片请求,也不会影响页面语义和可访问性。它能提前在布局中预留空间、统一尺寸、叠加渐变或骨架色块,等真实图片加载完成再通过 opacity 或 visibility 切换显示——这是纯 CSS 实现“视觉加载感”最轻量的方式。
关键前提是:必须已知图片宽高(或宽高比),否则占位会塌陷、导致布局抖动。
用 ::before 搭配 aspect-ratio 固定占位区域
现代浏览器(Chrome 88+、Firefox 89+、Safari 15.4+)支持 aspect-ratio,配合 ::before 可免 JS 计算宽高比:
.img-placeholder {
position: relative;
width: 100%;
aspect-ratio: 16 / 9; /* 替代 width/height 写死 */
background-color: #f5f5f5;
}
.img-placeholder::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, #f5f5f5 25%, #e0e0e0 50%, #f5f5f5 75%);
background-size: 200% 100%;
animation: loading-shimmer 2s infinite;
}
@keyframes loading-shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
-
aspect-ratio必须设在容器上,::before才能继承尺寸 - 若需兼容旧浏览器,改用
padding-top: 56.25%+position: absolute的经典响应式占位法 - 避免对
::before设置z-index: -1—— 它可能被父级overflow: hidden剪掉
图片加载完成时如何平滑替换占位层
不能靠监听 load 事件改 class(会破坏 SSR 和 SEO),推荐用 img 的 loading="lazy" + CSS :has()(Chrome 105+、Safari 15.4+)实现自动切换:
.img-container:has(img[src][loading]:not([src=""])) .img-placeholder::before {
opacity: 0;
transition: opacity 0.3s ease;
}
更稳妥的方案是服务端或构建时注入 class:
- 服务端渲染时,若图片 URL 已确定且非空,直接加
loaded类:<div class="img-container loaded"> <li>前端 JS 加载后手动添加:<code>img.addEventListener('load', () => el.classList.add('loaded')) - 对应 CSS:
.img-container.loaded .img-placeholder::before { display: none; }(比opacity: 0更节省重绘) - 图片原始宽高比和占位器不一致 → 视觉拉伸或留白;必须按图片真实
width/height属性或响应式断点分别设置aspect-ratio - 用
background-position动画时,若未加will-change: background-position或动画帧率低,会在低端安卓机上卡顿;建议改用transform: translateX()驱动动画 -
::before默认是 inline 元素,content: ""必须写,否则不渲染;某些 CSS 重置库会清空content,要显式覆盖
容易被忽略的细节:宽高比错位与骨架动画卡顿
实际项目中最常出问题的是两个地方:
真正难的不是写几行 CSS,而是让每个图片容器都准确知道自己的宽高比,并在不同加载阶段保持视觉节奏一致。











