延迟加载背景图片

延迟或懒加载背景图片以实现更快的 Largest Contentful Paint

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2024-11-27

延迟加载背景图片。

背景图片对 Core Web Vitals 来说很少是好事。背景图片不具备响应式特性,背景图片无法使用原生 loading 属性,我们也无法原生控制背景图片的优先级。

背景图片经常会导致 Core Web Vitals 出现问题。延迟加载不重要的背景图片在很多情况下会改善你的 Core Web Vitals。

我经常看到这种在网站上使用背景图片的反模式。尤其是在使用 elementor 等页面构建器的 WordPress 网站上。

  1. 所有图片,包括 LCP 图片(首屏大图)都被懒加载了
  2. 一些并不重要的图片元素(如间隔图片、搜索框背景等)在样式表中被设置为背景图片

lazy vs eager background images

在这篇小文章中,我将向你展示如何懒加载这些背景图片,以便优先加载页面上其他更重要的图片。

警告!

首先让我提出一个警告!当 LCP 元素因背景图片而延迟时,说明已经犯了错误,你应该优先用正确的方式修复它们(预加载 LCP 图片、不要懒加载 LCP 图片、完全避免使用背景图片)。不幸的是,有时遗留问题太多,你在短期内没有其他替代方案,只能尽最大努力修补网站。这就是你可以应用我今天展示的修复方法的时候!

方法一:延迟所有内容 

延迟所有内容的方法只是一种粗暴的做法。但它易于实现,而且能很好地改善 Core Web Vitals!使用此方法,所有背景图片都会被延迟到 DOMContentLoaded 事件触发之后。这将给浏览器一点额外的时间来优先调度最重要的资源。

以下是涉及的步骤:首先我们将覆盖所有具有背景图片的元素的 background-image 样式属性。一旦 DOM 内容加载完毕,我们将再次移除此覆盖。届时非背景图片将已经排队下载。这将是一个将不太重要的背景图片加入下载队列的好时机。

代码

首先创建一个样式并将其放在页面的 HEAD 中。重要的是这个样式要有一个 id,因为我们稍后会使用这个 id 来移除这个样式标签。当然,除了通配符(*)之外,你也可以只添加实际具有背景图片的 CSS 类名。

<style id="no-bg-img">
    *{background-image:none!important}
</style>

接下来,当 DOM 内容加载完毕后,LCP 图片可能已经排队等待下载。此时可以安全地将背景图片加入队列。

<script>
    window.addEventListener('DOMContentLoaded',function(){
        document.getElementById('no-bg-img').remove();
    })
</script>

如果 LCP 没有触发提前下载,这可能是由于 JavaScript 造成的。在这种情况下,你可以尝试将 'DOMContentLoaded' 替换为 'load' 事件。

之前

late lcp caused by background image

之后

early lcb after lazy background images

方法二:懒加载背景图片

懒加载背景图片的方法稍微更温和、更高级,需要更多的个性化处理。

其工作方式如下:首先我们要手动识别所有具有背景图片的元素。我们需要为这些元素添加一个类名(.lazybg)。然后我们将使用 intersection observer 观察这些元素,一旦它们接近可见视口,我们就会懒加载背景图片。

代码

首先创建一个样式并将其放在页面的 HEAD 中。这个样式与前一个样式类似,但不是移除页面上所有元素的背景图片属性,而是只移除具有特定类名的元素的背景图片属性。

<style>
    .lazybg {background-image: none !important}
</style>

接下来,当 DOM 内容加载完毕后,我们将开始观察具有背景图片的元素。当该元素滚动到视口中时,我们将移除 .lazybg 类以触发背景图片下载。

<script>
window.addEventListener('DOMContentLoaded', (event) => {

  // all elements wioth background images that should be lazy loaded 
  const lazyImages = document.querySelectorAll('.lazybg');
 
  // options for the observer
  const backgroundOptions = {
     threshold: 0,
     rootMargin: "0px 0px 50px 0px"
  };

  // the observer
  const imageObserver = new IntersectionObserver((entries, imageObserver) => {
     entries.forEach(entry => {
         if (entry.isIntersecting) {
             showImageBackground(entry.target);
             imageObserver.unobserve(entry.target);
         }
     });
  }, backgroundOptions);

    
  // observe each image
  lazyImages.forEach(image => {
     imageObserver.observe(image);
  });

  // show background image
  function showImageBackground(node) {
     node.classList.remove('lazybg');
  }
});
</script>

此方法的优势在于不在可见视口中的背景图片不会被排队下载。这在加载阶段为浏览器释放了资源。

之前

late lcp caused by background image

之后

background images delayed with the intersection observer

结论

两种方法都能有效地延迟背景图片,以优先加载更重要的图片,如 Largest Contentful Paint 图片。第一种方法非常容易实现,能快速获得结果。第二种方法为背景图片添加了真正的懒加载行为,将带来更大的页面速度提升。

应用这些方法时要小心。如果你需要延迟加载背景图片,那么你的页面就是我所说的"设计上就很慢"。修复此问题的首选方法是重写你的页面并避免使用背景图片。

Compare your segments.

Is iOS slower than Android? Is the checkout route failing INP? Filter by device, route, and connection type.

Analyze Segments >>

  • Device filtering
  • Route Analysis
  • Connection Types
延迟加载背景图片Core Web Vitals 延迟加载背景图片