图片异步加载是优化网页性能的重要技术,可以减少初始页面加载时间,提升用户体验。以下是几种实现图片异步加载的方法:

1. 使用 loading="lazy" 属性(原生懒加载)

<img src="image.jpg" loading="lazy" alt="示例图片">

这是HTML5原生支持的懒加载方式,现代浏览器都支持。当图片接近视口时才会加载。

2. 使用Intersection Observer API(更灵活的懒加载)

<img class="lazy" data-src="image.jpg" alt="示例图片">

<script>
document.addEventListener("DOMContentLoaded", function() {
  const lazyImages = document.querySelectorAll("img.lazy");
  
  if ("IntersectionObserver" in window) {
    const imageObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src;
          img.classList.remove("lazy");
          imageObserver.unobserve(img);
        }
      });
    });
    
    lazyImages.forEach(img => imageObserver.observe(img));
  } else {
    // 回退方案
    lazyImages.forEach(img => {
      img.src = img.dataset.src;
    });
  }
});
</script>

3. 使用低质量图片占位符(LQIP)

<img src="low-quality-placeholder.jpg" 
     data-src="high-quality-image.jpg" 
     class="lazy" 
     alt="示例图片">

4. 响应式图片的懒加载

<picture>
  <source data-srcset="large.jpg" media="(min-width: 1200px)">
  <source data-srcset="medium.jpg" media="(min-width: 768px)">
  <img src="placeholder.jpg" data-src="small.jpg" class="lazy" alt="响应式图片">
</picture>

5. 使用第三方库

常用的图片懒加载库:

  • lozad.js - 轻量级Intersection Observer实现

  • lazysizes - 功能丰富的懒加载库

最佳实践

  1. 为懒加载图片设置合适的宽高,避免布局偏移

  2. 使用占位符保持布局稳定

  3. 对关键图片(如首屏图片)不要使用懒加载

  4. 考虑使用模糊或低质量图片作为初始占位

  5. 为不支持JavaScript的环境提供回退方案

注意事项

  • 懒加载可能会影响SEO,确保搜索引擎爬虫能访问到重要图片

  • 过度使用懒加载可能会延迟内容显示,需要平衡

  • 移动设备上可能需要调整触发加载的阈值

如果文章内的插图没有原生的loading="lazy"标签,可以通过以下几种方法实现异步加载:

方法1:JavaScript动态添加loading属性(最简单)

// 在DOM加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
  // 获取所有文章内的img标签(假设文章在<article>内)
  const articleImages = document.querySelectorAll('article img');
  
  // 为每个图片添加loading="lazy"属性
  articleImages.forEach(img => {
    img.loading = 'lazy';
  });
});

 方法2:Intersection Observer API实现(更灵活)

document.addEventListener('DOMContentLoaded', function() {
  const images = document.querySelectorAll('article img:not([loading])');
  
  if ('IntersectionObserver' in window) {
    const imgObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          // 如果图片使用了data-src属性
          if (img.dataset.src) {
            img.src = img.dataset.src;
          }
          imgObserver.unobserve(img);
        }
      });
    }, {
      rootMargin: '200px 0px' // 提前200px加载
    });

    images.forEach(img => {
      // 如果图片没有src属性但有data-src,先不加载
      if (!img.src && img.dataset.src) {
        imgObserver.observe(img);
      }
      // 如果有src但想延迟加载,可以这样处理
      else if (img.src) {
        const originalSrc = img.src;
        img.removeAttribute('src');
        img.dataset.src = originalSrc;
        imgObserver.observe(img);
      }
    });
  } else {
    // 不支持IntersectionObserver的备用方案
    images.forEach(img => {
      if (img.dataset.src) {
        img.src = img.dataset.src;
      }
    });
  }
});

方法3:滚动事件监听(兼容旧浏览器)

function lazyLoadImages() {
  const images = document.querySelectorAll('article img:not([loading])');
  const windowHeight = window.innerHeight;
  
  images.forEach(img => {
    const imgPosition = img.getBoundingClientRect().top;
    
    if (imgPosition - windowHeight <= 0) {
      // 如果使用data-src属性
      if (img.dataset.src && !img.src) {
        img.src = img.dataset.src;
      }
      // 如果直接是src属性
      else if (!img.src && img.hasAttribute('src')) {
        // 不做处理,因为已经有src属性
      }
    }
  });
}

// 初始加载可视区域内的图片
document.addEventListener('DOMContentLoaded', lazyLoadImages);

// 滚动时加载
window.addEventListener('scroll', lazyLoadImages);
window.addEventListener('resize', lazyLoadImages);

方法4:使用第三方库(推荐lazysizes)

  1. 首先引入lazysizes库:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/lazysizes.min.js" async></script>

     

  2. 然后修改图片标记(无需修改已有HTML,通过JS自动处理):

    document.addEventListener('DOMContentLoaded', function() {
      const images = document.querySelectorAll('article img:not([loading])');
      
      images.forEach(img => {
        if (!img.classList.contains('lazyload')) {
          // 如果图片已经有src属性
          if (img.src) {
            img.dataset.src = img.src;
            img.removeAttribute('src');
          }
          img.classList.add('lazyload');
        }
      });
    });

最佳实践建议

  1. 占位符处理:为异步加载的图片添加占位样式,避免布局跳动

    img[data-src] {
      background: #f1f1f1;
      min-height: 100px; /* 根据你的设计调整 */
    }

 2.错误处理:添加图片加载失败的回调

images.forEach(img => {
  img.onerror = function() {
    this.style.display = 'none';
    // 或者显示一个错误占位图
  };
});

3.优先级处理:首屏图片不要延迟加载

// 获取首屏内的图片并立即加载
const firstScreenImages = document.querySelectorAll('article img:not([loading])');
firstScreenImages.forEach(img => {
  const rect = img.getBoundingClientRect();
  if (rect.top < window.innerHeight && rect.bottom > 0) {
    if (img.dataset.src) img.src = img.dataset.src;
  }
});

4.SEO友好:确保搜索引擎能抓取到图片内容

<!-- 使用noscript标签为禁用JS的环境提供备用 -->
<noscript>
  <img src="real-image.jpg" alt="描述文本">
</noscript>

选择哪种方法取决于你的项目需求:

  • 现代浏览器项目:方法1或方法2

  • 需要广泛兼容性:方法3或方法4

  • 复杂项目:推荐使用lazysizes库