分析一个网站的加载性能时,经常会遇到这样的问题:页面下面有几十张图片,它们到底是在打开网页时一次性全部下载,还是等用户滚动到附近才开始加载?

从页面视觉效果并不能准确判断。有些图片虽然滚动之后才“显示”,资源实际上早已下载完成,只是通过CSS动画延迟出现;也有些图片在HTML中已经存在,但浏览器会因为设置了loading="lazy"而推迟网络请求。还有一类网站完全依靠JavaScript监听滚动位置,在元素接近可视区域后才设置真正的图片地址。

因此,判断网页元素有没有使用懒加载,最好同时检查HTML结构和实际网络请求。Chrome DevTools中的Elements与Network面板就是最直接的排查工具。

网站懒加载怎么检查?从loading属性到Network请求逐步判断

网页懒加载到底是什么

Lazy Loading,也就是懒加载或延迟加载,核心目的并不是“让元素晚一点出现”,而是把暂时不需要的资源推迟到真正可能使用时再加载。

例如一篇长文章有30张图片,用户刚打开页面时只能看到前两张。如果浏览器立即下载全部30张图片,会消耗更多带宽,也可能与首屏的重要资源竞争网络连接。

使用懒加载后,首屏之外的图片可以等用户滚动到附近时再请求。

MDN目前将Lazy Loading描述为一种把非关键资源推迟到需要时再加载的性能优化策略。图片、iframe等屏幕外资源都是比较常见的应用对象。

因此,真正判断是否懒加载时应该关注两个问题:

  • 资源什么时候发起网络请求。

  • 是什么机制决定了这个请求时间。

先检查loading属性

目前判断图片和iframe是否使用浏览器原生懒加载,最简单的方法就是检查HTML。

在Chrome中右键目标图片,选择“检查”,进入Elements面板。如果看到类似代码:

<img
  src="https://example.com/photo.jpg"
  loading="lazy"
  alt="图片说明"
>

就说明开发者明确要求浏览器对这张图片使用原生懒加载。

iframe也可以使用相同机制:

<iframe
  src="https://example.com/player"
  loading="lazy"
></iframe>

loading常见值包括:

属性值含义
loading="lazy"允许浏览器延迟加载屏幕外资源
loading="eager"倾向立即加载资源
没有loading属性默认不是通过这一HTML属性声明懒加载

这里最后一种情况需要特别注意:没有loading="lazy",并不代表网页没有懒加载,因为网站还可能通过JavaScript自己实现。

可以快速查出所有原生懒加载

如果页面很长,不想逐个检查图片,可以打开Chrome DevTools的Console面板执行:

document.querySelectorAll('img[loading="lazy"]')

浏览器会返回当前DOM中所有明确设置了原生图片懒加载的元素。

如果同时想检查iframe,可以使用:

document.querySelectorAll('img[loading="lazy"], iframe[loading="lazy"]')

也可以快速统计数量:

document.querySelectorAll(
  'img[loading="lazy"], iframe[loading="lazy"]'
).length

这种方法适合快速检查原生Lazy Loading,但无法发现所有JavaScript实现。

看到data-src通常要继续检查

在较早的懒加载方案以及部分JavaScript插件中,经常不会一开始就把真实图片地址直接放进src

例如:

<img
  src="placeholder.jpg"
  data-src="real-image.jpg"
  class="lazyload"
>

或者:

<img
  data-src="image.jpg"
  data-srcset="image-800.jpg 800w, image-1200.jpg 1200w"
>

页面刚打开时,真正的图片地址保存在data-srcdata-srcset中。当JavaScript检测到元素接近视口以后,再把地址复制到srcsrcset

滚动之后可能变成:

<img
  src="real-image.jpg"
  data-src="real-image.jpg"
  class="loaded"
>

如果检查元素时发现data-srcdata-srcsetlazylazyload之类的属性或类名,通常值得进一步检查。

不过这些名称本身只是线索,并不能作为最终证据。网站开发者可以随意命名CSS类,真正是否延迟下载仍然应该到Network面板确认。

Network面板判断更加可靠

如果真正想知道资源是不是延迟加载,观察网络请求通常比单纯检查HTML更加可靠。

可以按照下面的方法测试:

  1. 打开Chrome DevTools。

  2. 进入Network面板。

  3. 勾选Disable cache,避免缓存影响测试。

  4. 保持页面停留在顶部并重新刷新。

  5. 选择Img过滤图片资源。

  6. 找到位于页面很下面的目标图片。

  7. 先不要滚动,观察它是否已经产生请求。

  8. 逐渐向下滚动,再观察Network是否出现新的图片请求。

如果目标图片在刷新时没有请求,滚动到接近该元素时才突然出现在Network列表中,就可以比较明确地判断这张图片存在延迟加载行为。

对于iframe,可以查看对应Document请求;视频、接口返回内容或者动态组件,则可以结合Media、Fetch/XHR等资源类型进行观察。

为什么滚动前也可能看到请求

原生loading="lazy"并不意味着图片必须进入屏幕之后才开始下载。

浏览器会根据自己计算的距离,在元素真正进入可视区域之前提前发起请求。这样做是为了避免用户滚动到图片位置时还需要面对明显的空白等待。

因此可能出现这样的情况:

一张图片距离当前视口还有一段距离,但Network中已经出现了它的请求,同时HTML仍明确设置了loading="lazy"

这种情况不能因此判断懒加载“失效”。浏览器原生懒加载本身就是由浏览器决定合适的提前加载距离,而不是简单执行“进入屏幕才下载”。

所以实际检测时,HTML属性和网络行为最好结合起来判断。

JavaScript懒加载怎么判断

除了原生HTML属性,网站还可以使用JavaScript实现更复杂的懒加载。

目前一种常见方案是Intersection Observer API。

它能够监听一个元素什么时候接近或进入浏览器视口,因此非常适合处理图片懒加载、无限滚动和延迟渲染。

典型代码逻辑可能类似:

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
});

这段逻辑的核心就是:先观察图片,发现图片进入指定范围后,再把data-src写入真正的src

如果怀疑网站使用这种方式,可以进入Sources面板搜索:

IntersectionObserver

还可以搜索:

data-src
data-srcset
lazyload
lazy
observer

如果网站JavaScript经过压缩或打包,代码可能不容易阅读,这时仍然建议回到Network面板直接观察结果。

检查属性滚动前后是否变化

还有一种比较直观的方法,是打开Elements面板观察目标元素。

假设滚动之前看到:

<img
  src="placeholder.svg"
  data-src="product.jpg"
>

滚动到图片附近后变成:

<img
  src="product.jpg"
  data-src="product.jpg"
>

这种变化基本可以确认页面脚本在接近显示区域时替换图片来源。

有些库还会改变class,例如:

class="lazy"

加载后变为:

class="lazy loaded"

这些变化都有助于判断懒加载具体由哪套程序实现。

CSS背景图片怎么判断

网页中的图片不一定都使用<img>

例如网站Banner可能写成:

.banner {
  background-image: url("banner.jpg");
}

这种图片没有loading="lazy"属性可以检查,因为它属于CSS背景资源。

如果开发者希望延迟加载背景图片,通常需要通过JavaScript在元素接近视口后动态添加class或者修改style。

例如最初:

<div class="banner"></div>

滚动以后:

<div class="banner loaded"></div>

然后CSS才变成:

.banner.loaded {
  background-image: url("banner.jpg");
}

对于这种情况,最可靠的方法依然是同时观察Elements中的样式变化和Network中的图片请求时间。

iframe也经常使用懒加载

除了图片,YouTube视频、地图、广告以及第三方组件通常通过iframe嵌入页面,而iframe本身可能包含HTML、JavaScript、CSS和更多网络资源。

因此屏幕外iframe往往也是值得延迟加载的对象。

最直接的原生写法是:

<iframe
  src="https://example.com/embed"
  loading="lazy"
></iframe>

MDN目前的HTML说明中,iframe的loading="lazy"会提示浏览器推迟加载距离可视区域较远的iframe。

检测方法和图片基本相同:先检查HTML属性,然后到Network中观察iframe对应的Document请求什么时候出现。

滚动后出现不一定是懒加载

这是判断网页懒加载时最容易出现的误区。

一个元素滚动到屏幕里以后才显示,不代表它的资源也是那个时候才下载。

例如网站可能在页面加载时已经下载图片,只是设置:

opacity: 0;

进入视口后通过动画改成:

opacity: 1;

视觉效果看起来像“滚动到这里才加载”,实际上Network会发现图片在页面刚打开时就已经下载。

类似的动画库、滚动特效、淡入效果都可能产生这种错觉。

所以区分“延迟显示”和“延迟下载”非常重要。真正意义上的资源懒加载,应该能够看到网络请求被推迟。

无限滚动和懒加载也不完全相同

另外一种容易混淆的机制是Infinite Scroll,也就是无限滚动。

图片懒加载通常意味着元素已经存在于当前页面中,只是对应资源延迟下载。

而无限滚动可能是用户滚动到底部以后,浏览器才通过Fetch或XHR向服务器请求下一批文章、商品或图片,然后创建新的DOM元素。

例如首页打开时只有20件商品,滚动到底部后发送:

/api/products?page=2

再把第二页商品插入当前页面。

这种模式当然也属于延迟获取内容的性能策略,但在分析网页结构时,最好把“已有元素资源懒加载”和“滚动后动态请求新内容”区分开。

可以用Console辅助排查

对于图片页面,还可以使用一些简单的Console命令快速寻找可能存在的懒加载实现。

检查原生懒加载:

[...document.images].filter(img => img.loading === 'lazy')

检查带有data-src的图片:

[...document.images].filter(img => img.dataset.src)

检查data-srcset:

[...document.images].filter(img => img.dataset.srcset)

检查图片是否已经完成加载:

[...document.images].map(img => ({
  src: img.currentSrc || img.src,
  loading: img.loading,
  complete: img.complete
}))

其中complete只能说明当前图片是否完成加载,不能单独证明它原来是不是懒加载,因此仍然应该配合其他方法。

首屏图片不宜全部懒加载

发现网页使用懒加载之后,还需要判断使用位置是否合理。

懒加载并不是越多越好。

页面首屏的重要图片,特别是可能成为Largest Contentful Paint,也就是LCP元素的大图,通常不适合因为不必要的懒加载而推迟请求。

懒加载更适合页面首屏之外的非关键图片和iframe。对于用户一打开网页就需要看到的Logo、Hero图片和主要内容图片,更重要的是让浏览器尽早发现和加载资源。

因此,检测Lazy Loading不仅用于确认“网站有没有做性能优化”,还可以进一步发现“哪些元素不应该被延迟,却错误设置了lazy”。

参考资料

  1. MDN Lazy Loading性能指南

  2. MDN图片loading属性说明

  3. MDN iframe loading属性说明

  4. MDN Intersection Observer API文档

  5. Chrome DevTools官方文档