原生 loading="lazy" 在 chrome 76+、firefox 75+、edge 79+ 中最快生效,无需 js 即可实现图片懒加载,但需确保 width/height 存在且仅用于非首屏可见元素。

img 标签加 loading="lazy" 最快生效
现代浏览器(Chrome 76+、Firefox 75+、Edge 79+)原生支持 loading="lazy",无需 JS 就能对图片做懒加载。只要在 <img> 上加上这个属性,浏览器会在图片进入视口前不发起请求,滚动到附近时才开始加载。
注意:该属性只对 <img> 和 <iframe></iframe> 生效,且仅适用于非首屏、非 display: none 或 visibility: hidden 的元素。
- 必须确保图片有明确的
width和height(或通过 CSS 设置),否则可能引发布局偏移(CLS) - 不要和
background-image混用——CSS 背景图不支持loading属性 - 服务端渲染(SSR)场景下,该属性会直接输出到 HTML,无需额外处理
IntersectionObserver 是最可控的 JS 方案
当需要兼容老浏览器、自定义加载阈值、或配合占位图/动画时,IntersectionObserver 是首选。它比监听 scroll 事件更轻量、更精准,且不会触发强制同步布局。
典型写法是把真实图片地址存在 data-src 里,首次进入视口时再赋给 src:
@@##@@
JS 部分示例:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
}, { threshold: 0.1 }); // 进入视口 10% 即触发
document.querySelectorAll('img.lazy').forEach(img => observer.observe(img));
-
threshold设为0表示完全进入视口才加载;设为0.1可提前加载,减少滚动时白屏感 - 加载完成后务必调用
observer.unobserve(),否则会持续监听已加载图片,浪费资源 - 如果图片被动态插入(如 AJAX 渲染),需在插入后显式调用
observer.observe()
慎用 onload + display:none 触发加载
有些旧方案用 onload 回调配合 display: none 切换来“模拟懒加载”,这其实无效甚至有害:
-
display: none的<img class="lazy">在大多数浏览器中仍会加载(Chrome/Firefox 均如此),只是不渲染 - 用
visibility: hidden同样无法阻止请求发起 - 靠
onload控制显示时机,本质是“加载完再显示”,不是“按需加载”,起不到节省带宽和首屏时间的作用
真正要延迟加载,必须延迟 src 赋值,而不是延迟显示。
第三方库如 lazysizes 要看实际需求
lazysizes 是个成熟方案,支持响应式图片(srcset、sizes)、低质量占位图(LQIP)、WebP 自动降级等,适合复杂项目。
但它引入了额外体积(约 5KB gzip),且多数新项目用原生 loading="lazy" 已足够。只有当你遇到以下情况才值得引入:
- 需要支持 IE 或低于 Chrome 76 的版本
- 大量使用
<picture></picture>+srcset,且要精确控制不同 DPR 下的懒加载时机 - 依赖其插件生态(比如 blur-up 效果、自动监听页面变化)
用法上,它依赖 data-src 和 class="lazyload" 触发,和手写 IntersectionObserver 逻辑类似,但封装了兼容性处理。
懒加载真正的难点不在“怎么加”,而在“加在哪”——首屏关键图不能懒,width/height 缺失会抖动,data-src 写错路径会导致 404 静默失败。这些细节比选方案更容易出问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











