HTML图片懒加载实现教程:loading属性、IntersectionObserver与性能优化

图片通常是网页里最占体积的资源之一。一个页面文字内容可能只有几十 KB,但几张高清图片就能轻松达到几 MB。如果所有图片都在页面打开时一次性加载,首屏速度、移动端流量、服务器带宽都会受到影响。

HTML 图片懒加载的核心思路很简单:用户暂时看不到的图片先不加载,等快要进入可视区域时再加载。这样既能缩短首屏加载时间,也能减少无效请求。本文从原生 loading 属性讲起,再到 IntersectionObserver 自定义懒加载,最后补充性能优化和常见坑。

懒加载适合什么场景

懒加载最适合图片多、页面长、首屏以下资源较重的页面,比如文章详情页、产品列表页、相册页、博客首页、专题页。用户打开页面时,只需要先看到首屏内容,下面的图片可以等滚动到附近再加载。

但并不是所有图片都应该懒加载。首屏核心图片、Logo、头图、影响页面主要视觉结构的图片,通常应该正常加载。如果首屏大图也懒加载,可能会让用户看到明显空白,反而影响体验。

loading 属性

现代浏览器已经支持原生图片懒加载,只需要给 img 标签添加 loading="lazy"。这是最简单、维护成本最低的懒加载方式。

<img src="/images/article-cover.jpg" alt="文章配图">

loading 常见取值有三个:lazy 表示延迟加载,eager 表示立即加载,auto 表示交给浏览器自行判断。实际项目里最常用的是 lazy

HTML图片懒加载与网页性能优化示意图
图片懒加载的目标不是让图片更小,而是让浏览器优先加载用户马上需要看到的内容。

宽高不能省

给图片做懒加载时,一定要尽量写明 widthheight。如果浏览器不知道图片尺寸,图片加载完成后可能把页面内容往下挤,造成明显的布局跳动。

<img
  src="/images/demo.jpg"
  alt="示例图片"
  width="800"
  height="450"
 >

布局跳动会影响用户阅读体验,也会影响页面性能指标中的 CLS。对于文章页和产品列表页,图片尺寸固定后,浏览器可以提前预留空间,页面滚动会更稳定。

首屏图片不要懒加载

很多人为了省事,会给页面里所有图片统一加上 loading="lazy",这并不总是正确。首屏大图、文章顶部封面、商品主图等关键图片通常应该使用正常加载,甚至可以配合预加载优化。

<img src="/images/hero.jpg" alt="首屏主图">

如果首屏图片被懒加载,浏览器可能会降低它的加载优先级,导致页面主要内容迟迟不完整。判断标准很简单:用户打开页面马上能看到的图片,不要轻易懒加载;需要向下滚动才能看到的图片,才适合懒加载。

IntersectionObserver 原理

如果需要兼容更复杂的业务,比如加载前显示占位图、进入视口前提前 200 像素加载、图片加载失败后替换兜底图,就可以使用 IntersectionObserver

它可以观察某个元素是否进入指定区域。相比监听 scroll 事件再反复计算位置,IntersectionObserver 更高效,也更适合大量图片场景。

<img
  src="/images/placeholder.jpg"
 
  alt="真实图片"
  class="lazy-image"
  width="800"
  height="450">

上面的写法先把占位图放到 src,真实图片地址放到 data-src。等图片接近可视区域时,再用 JavaScript 把 data-src 的值赋给 src

自定义懒加载代码

下面是一个基础版实现。为了避免触发部分网站安全策略,示例只展示 JavaScript 逻辑,不把代码包在页面脚本标签里。

const lazyImages = document.querySelectorAll('.lazy-image');

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (!entry.isIntersecting) return;

    const img = entry.target;
    img.src = img.dataset.src;
    img.classList.add('is-loaded');
    observer.unobserve(img);
  });
}, {
  root: null,
  rootMargin: '200px 0px',
  threshold: 0.01
});

lazyImages.forEach((img) => observer.observe(img));

rootMargin 可以让图片在进入视口前提前加载。比如 200px 0px 表示图片距离视口还有 200 像素时就开始加载,用户继续下滑时更不容易看到空白。

兼容降级

现在主流浏览器已经支持 IntersectionObserver,但如果你需要兼容旧环境,最好加一个降级逻辑:如果浏览器不支持,就直接加载所有图片,保证内容可见。

if (!('IntersectionObserver' in window)) {
  lazyImages.forEach((img) => {
    img.src = img.dataset.src;
  });
}

降级策略的目标不是做到极致性能,而是保证页面可用。旧浏览器用户即使不能享受懒加载优化,也应该能正常看到图片内容。

配合响应式图片

懒加载解决的是加载时机,不解决图片尺寸本身。如果移动端仍然加载桌面端大图,页面还是会浪费流量。更好的做法是配合 srcsetsizes,让浏览器按屏幕宽度选择合适图片。

<img
  src="/images/photo-800.jpg"
  srcset="/images/photo-400.jpg 400w, /images/photo-800.jpg 800w, /images/photo-1200.jpg 1200w"
  sizes="(max-width: 600px) 100vw, 800px"
  alt="响应式图片示例"
 
  width="800"
  height="450">

这样移动端可以加载较小图片,桌面端再加载更大图片。对于图片较多的网站,这类优化往往比单纯加懒加载更明显。

常见错误

第一类错误是懒加载首屏关键图,导致 LCP 变差。第二类错误是不写图片宽高,导致图片加载后页面抖动。第三类错误是只把真实图片放进 data-src,但没有任何降级方案,结果部分环境图片永远不显示。

还有一种常见问题是懒加载距离设置太近。图片已经进入视口才开始请求,用户会看到明显空白。通常可以通过 rootMargin 提前加载,让体验更平滑。

性能优化建议

懒加载只是图片优化的一部分。上线前还要检查图片是否经过压缩,是否使用合适格式,是否有 WebP 或 AVIF 版本,是否配置了缓存策略。对于 WordPress 站点,还要注意主题和插件是否已经自动添加懒加载,避免重复处理。

如果页面图片来自媒体库,建议上传前就控制尺寸,不要把几千像素宽的原图直接塞进正文。文章页常见正文宽度并不需要超大原图,图片越贴近实际展示尺寸,加载速度越稳定。

实践顺序

实际开发中,可以按这个顺序处理图片懒加载:首屏关键图正常加载;正文和列表里的非首屏图片添加 loading="lazy";所有图片补齐 widthheight;复杂场景再使用 IntersectionObserver;最后用浏览器开发者工具检查网络请求和布局跳动。

如果只是普通文章页,原生 loading="lazy" 已经足够好用;如果是图片瀑布流、商品列表或相册页面,再考虑自定义懒加载逻辑。优化的关键不是代码越复杂越好,而是让首屏更快、滚动更稳、图片请求更合理。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容