图片加载前黑屏源于img透明且父容器无背景色,需为容器设position:relative并用::before伪元素加背景色,配合opacity过渡和complete检测防闪屏。

图片加载前黑屏是因为没有设置占位背景
移动端图片加载慢时出现黑屏,本质是 <img> 元素默认透明,而父容器又没设背景色,导致空白区域透出底层黑色(尤其在深色模式或 WebView 黑底环境下)。这不是图片本身问题,而是渲染节奏没对齐。
- 只靠
loading="lazy"或压缩图片尺寸无法解决首帧黑屏 -
background-color必须作用于图片容器(如<div>),不能只写在 <code><img>上——<img>自身不支持背景色填充未加载区域 - 用 CSS
aspect-ratio配合背景色,能避免布局偏移(reflow),比 JS 计算宽高更轻量 - 容器需设
position: relative,否则伪元素定位会错乱 - 伪元素必须设
content: ""和display: block才能生效 - 图片加载完成瞬间可能闪一下,加
transition: opacity 0.2s到<img>可缓解
用伪元素 + background-color 实现可靠预加载底色
直接给容器设 background-color 最简单,但若要区分加载中/失败状态,推荐用 ::before 伪元素控制底色层,让图片层自然叠在其上。这样既不影响图片事件,又能独立控制过渡和 fallback。
div.img-container {
position: relative;
aspect-ratio: 16 / 9;
}
div.img-container::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background-color: #f5f5f5;
}
div.img-container img {
width: 100%; height: 100%; object-fit: cover;
opacity: 0;
transition: opacity 0.2s;
}
div.img-container img.loaded {
opacity: 1;
}
JS 监听 load 事件时容易漏掉 cached 图片
用 img.onload 给图片加 loaded 类很常见,但若图片已缓存,load 事件可能在 JS 执行前就触发了,导致类没加上、opacity 始终为 0。
- 必须在设置
src之前就绑定onload,顺序不能反 - 更稳妥的做法是检查
img.complete === true,立即处理已加载状态 - 不要依赖
document.readyState === "complete",它不保证图片资源就绪
const img = document.querySelector("img");
if (img.complete) {
img.classList.add("loaded");
} else {
img.addEventListener("load", () => img.classList.add("loaded"));
}
// 注意:src 赋值必须在 addEventListener 之后
深色模式下预设背景色要适配系统偏好
硬写死 #f5f5f5 在深色模式里会突兀。用 color-scheme: light dark + prefers-color-scheme 媒体查询可自动切换,但注意 Safari 对伪元素内媒体查询支持不稳定。
- 推荐用 CSS 自定义属性 + JS 检测,兼容性更好:
document.documentElement.classList.toggle("dark", window.matchMedia("(prefers-color-scheme: dark)").matches) - 避免用
background-image: url(data:...)当占位,Base64 数据过大时反而拖慢首屏 - 如果项目已用 Tailwind,可用
dark:bg-gray-800类,但需确认dark:前缀已启用
CSS 预加载底色这事,核心不在“怎么写”,而在“什么时候生效”——图片是否已解码、容器是否已生成、伪元素是否被重绘,三个时间点稍有错位就会露黑。别迷信单一样式规则,得把加载流程拆成“占位→请求→解码→渲染”四步,每步都留个兜底。











