渐进式图片加载需LQIP占位图、JS替换逻辑与CSS过渡三者配合:src指向200px宽3–5%质量JPG占位图,data-src存高清图地址,用IntersectionObserver监听视口并触发替换,CSS同时控制filter和opacity实现平滑过渡。

渐进式图片加载不是靠一个属性就能搞定的事,loading="lazy"只管加载时机,不解决“模糊→清晰”视觉过渡;真正起作用的是占位图 + 替换逻辑 + CSS 过渡三者配合。
用 src 指向 LQIP,dataset.src 存高清图地址
这是最可控、兼容性好、不依赖第三方库的起点。LQIP(Low-Quality Image Placeholder)不是随便压缩的小图,而是 200px 宽、3–5% 质量的 JPG,体积控制在 10–20KB 内,能快速解码并撑起容器结构。
-
src必须指向这张小图,否则浏览器不会提前渲染占位,用户看到的就是空白或骨架屏 -
data-src(或data-srcset)存高清图路径,避免直接写在src里导致重复请求 - 不要用
lowsrc——它在所有现代浏览器中已被完全忽略,写了等于没写 - 如果用 base64 占位,长度别超 200 字节,否则拖慢 HTML 解析,影响 LCP
用 IntersectionObserver 替换 scroll 监听视口
滚动监听容易卡顿,尤其在低端安卓机或图片密集页;IntersectionObserver 是浏览器原生的异步检测机制,性能更稳,且能提前触发加载。
- 初始化时设
rootMargin: "50px",让图片在进入视口前 50px 就开始加载,避免滚动快时“跳入” -
threshold: 0.01比0更可靠,某些浏览器对 0 的判定有延迟或不触发 - 回调里替换
img.src = img.dataset.src后,立刻调用observer.unobserve(img),防止重复执行 - IE 不支持,但只需引入
intersection-observer-polyfill(仅 2KB),无需整套兼容方案
CSS 过渡必须同时控制 filter 和 opacity
只靠 opacity 淡入会暴露底图拉伸失真;只靠 filter: blur() 在高清图替换瞬间会有明显“闪帧”。两者叠加才能兼顾视觉平滑与结构稳定。
立即学习“前端免费学习笔记(深入)”;
- 初始样式:
img { filter: blur(6px); opacity: 1; transition: filter 0.4s ease, opacity 0.3s ease; } - 加载完成加
loaded类:.loaded { filter: blur(0); opacity: 1; } - 别用
transition: all——filter和opacity的过渡行为差异大,混在一起反而难调 - 移动端 Safari 对图像解码时机敏感,加
will-change: opacity可缓解闪动,但会略增内存开销
慎用 <picture> + <source> 做渐进加载
<picture> 本身不提供渐进能力,它只是资源选择器;想让它配合 LQIP,得手动控制 fallback 图片的加载顺序,否则浏览器可能跳过占位图直接加载 <source> 中匹配的高清图。
- 可行结构:外层
<picture>里放一个<img src="lqip.jpg">作为 fallback,再用 JS 动态往<source>插入高清地址 - 优势在于能利用浏览器原生的
srcset解析和缓存策略,适合 DPR 变化频繁(如横竖屏切换)的场景 - 风险是:若 JS 执行失败或延迟,
<picture>会退回到src,但此时src若指向 LQIP,就失去响应式能力——所以 fallback 图必须是可接受的最小尺寸图 - 不要指望
<source type="image/webp">自动帮你做渐进,它只选格式,不控制加载节奏
最容易被忽略的点是:渐进加载效果是否生效,不取决于 JS 是否跑通,而取决于 LQIP 图能否在高清图之前完成解码并渲染。这意味着你得确保小图尺寸足够小、格式足够简单(JPG > WebP > AVIF)、且服务器响应头没禁用缓存。



















