在现代网页开发中,图片是提升用户体验的重要元素,同时也是影响网页性能的主要瓶颈。随着网页内容的复杂化和图片数量的增加,一次性加载所有图片会导致页面加载速度变慢、服务器压力增大,甚至可能让用户在等待页面加载中流失。
为了解决这一问题,图片懒加载(Lazy Loading)应运而生,本文将结合深入解析图片懒加载的原理,希望看完的能有所收获。
一、什么是图片懒加载?
1.1 概念
图片懒加载是一种延迟加载技术,其核心思想是仅在用户需要查看图片时才加载图片。
具体来说就是,当用户滚动页面时,只有进入可视区域(窗口)的图片才会被加载,而未进入可视区域的图片则保持“惰性”状态,直到用户接近它们时才触发加载。
1.2 为什么要使用懒加载?
- 减少初始加载时间:页面首次加载时,仅加载首屏可见的图片,可以避免大量图片同时请求。
- 降低服务器压力:减少不必要的图片请求,尤其适用于高并发场景。
- 节省带宽和流量:用户可能不会滚动到页面底部,未加载的图片不会消耗用户的流量。
- 提升用户体验:页面加载速度更快,用户能更快看到核心内容。
二、懒加载的实现原理
2.1. 核心逻辑
懒加载的实现依赖于以下三个关键点:
- 检测元素是否进入可视区域:通过
getBoundingClientRect()方法判断图片是否在用户当前视口范围内。 - 延迟加载图片:使用
data-original属性存储真实图片地址,通过 JavaScript 动态赋值给src属性。 - 事件监听:监听页面的
scroll事件,实时检测图片是否进入可视区域。
2.2 关键技术点
data-original属性:这是 HTML5 中的自定义数据属性(data-XXX),用于存储真实图片的 URL。在页面加载时,src属性指向一个占位图或空值,而真实图片地址通过data-original保存,待用户滚动到可视区域时再赋值给src。getBoundingClientRect()方法:该方法返回元素相对于视口的位置信息,包括top、bottom、left、right等属性,可用于判断元素是否进入可视区域。Intersection Observer API:现代浏览器推荐使用的更高效的懒加载实现方式,能够替代传统的scroll事件监听。
下面,我将通过一段代码案例,带大家深入了解一下。
三、代码案例详解
3.1 基础代码
<img
class="image-item"
lazyload="true"
src="../../image/placeholder.gif" //占位图
data-original="https://example.com/real-image.jpg" //实际上要展示的图片
/>
src属性:指向一个占位图(如低分辨率的缩略图或纯色背景),确保图片容器在页面布局中占位。data-original属性:存储真实图片的地址,只有在用户滚动到该图片时才会被赋值给src。
3.2 JS 实现
const viewHeight = document.documentElement.clientHeight;
const eles = document.querySelectorAll('img[data-original][lazyload]');
window.lazyload = function () {
Array.prototype.forEach.call(eles, function (item, index) {
if (item.dataset.original === "") return;
let rect = item.getBoundingClientRect();
if (rect.bottom >= 0 && rect.top <= viewHeight) {
(function () {
var img = new Image();
img.src = item.dataset.original;
img.onload = function () {
item.src = item.dataset.original;
item.removeAttribute('data-original');
item.removeAttribute('lazyload');
};
})();
}
});
};
// 监听事件
document.addEventListener('DOMContentLoaded', lazyload);
window.addEventListener('scroll', lazyload);
3.2.1 代码解析
- 获取可视区域高度:
viewHeight表示用户当前视口的高度。 - 选择需要懒加载的图片:通过
querySelectorAll选择所有具有data-original和lazyload属性的<img>元素。 - 遍历图片并检测是否进入可视区域:
- 使用
getBoundingClientRect()获取图片的位置信息。 - 如果图片的
bottom位置大于等于 0,且top位置小于等于视口高度,则认为图片进入可视区域。
- 使用
- 加载真实图片:
- 创建内存中的
Image对象,预加载真实图片。 - 使用
onload事件确保图片加载完成后,将其赋值给src属性。 - 移除
data-original和lazyload属性,避免重复加载。
- 创建内存中的
3.2.2 注意事项
- 闭包的使用:代码中使用闭包包裹加载逻辑,确保每次加载的图片是独立的。
- 移除属性:加载完成后移除
data-original和lazyload属性,避免后续的scroll事件重复触发加载。 - 事件监听:在页面加载完成后(
DOMContentLoaded)和用户滚动时(scroll)触发懒加载逻辑。
四、优化策略
4.1 占位图的选择
在图片懒加载中,占位图的选择直接影响页面的初始加载性能和用户体验,以下为两种常见策略:
1. 低分辨率缩略图
- 原理:使用小尺寸、低质量的缩略图作为
src初始值,可以减少首次加载的资源体积。 - 实现方式:
<img src="low-res-image.jpg" data-original="high-res-image.jpg" /> - 优势:
- 显著降低初始页面加载时间,尤其适合图片密集型页面(如电商商品列表)。
- 用户能立即看到占位图,避免空白区域导致的视觉不适。
- 注意事项:
- 缩略图需保持与目标图片的宽高比一致,防止布局抖动。
- 若缩略图过大(如超过 50KB),可能抵消优化效果。
2. 纯色背景占位图
- 原理:使用与页面背景一致的纯色(如白色、灰色)填充图片容器,模拟真实图片的布局。
- 实现方式:
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-original="high-res-image.jpg" style="background-color: #000;" /> - 优势:
- 零字节请求,完全避免额外网络开销。
- 适用于所有屏幕尺寸,无需适配不同分辨率。
- 典型案例:
- 京东、淘宝等电商平台采用纯色占位图,确保页面首屏快速渲染。
4.2 防抖与节流
在传统懒加载实现中,频繁触发 scroll 事件会导致性能问题,通过 节流(Throttle) 和 防抖(Debounce) 技术可以显著优化。
1. 节流(Throttle)
- 原理:限制
scroll事件的触发频率,确保单位时间内只执行一次回调。 - 实现代码:
let ticking = false; window.addEventListener('scroll', () => { if (!ticking) { window.requestAnimationFrame(() => { lazyload(); // 执行懒加载逻辑 ticking = false; }); ticking = true; } }); - 优势:
- 利用
requestAnimationFrame与浏览器刷新率同步,减少无效计算。 - 比
setTimeout更精确,避免卡顿感。
- 利用
2. 防抖(Debounce)
- 适用场景:用户快速滚动后需要延迟执行懒加载(如无限滚动)。
- 实现代码:
let debounceTimer; window.addEventListener('scroll', () => { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { lazyload(); }, 200); // 200ms 内无滚动则执行 }); - 注意事项:
- 防抖可能导致部分图片加载延迟,需权衡用户体验与性能。
4.3 Intersection Observer API
Intersection Observer API 是现代懒加载的标准解决方案,替代了传统的 scroll + getBoundingClientRect() 方法。
1. 核心优势
- 异步非阻塞:由浏览器底层异步检测元素可见性,不依赖
scroll事件。 - 性能优化:
- 避免频繁调用
getBoundingClientRect()触发回流(Reflow)。 - 减少 JavaScript 执行频率,降低 CPU 占用。
- 避免频繁调用
2. 实现代码
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.original;
img.removeAttribute('data-original');
img.removeAttribute('lazyload');
observer.unobserve(img); // 停止观察已加载的图片
}
});
});
document.querySelectorAll('img[lazyload]').forEach(img => {
observer.observe(img);
});
3. 参数详解
threshold:设置触发回调的交集比例(如0.1表示元素 10% 进入视口时触发)。rootMargin:扩展/缩小检测区域(如"0px 0px 200px 0px"表示提前 200px 加载图片)。
4. 与传统方案对比
| 特性 | 传统方案(scroll + getBoundingClientRect) | Intersection Observer API |
|---|---|---|
| 回流触发 | 高频触发,性能差 | 无回流 |
| 代码复杂度 | 复杂,需手动管理事件 | 简洁 |
| 兼容性 | 全面支持 | 需 Polyfill 支持 IE |
| 动态内容适配 | 需手动重新监听 | 自动适配新增元素 |
4.4 响应式图片
通过 srcset 和 sizes 属性,可以根据设备分辨率动态加载不同尺寸的图片,进一步优化带宽和加载速度。
1. srcset 与 sizes 的协同工作
srcset:提供多组图片路径及对应的宽度描述符(如1920w)。sizes:定义不同屏幕宽度下的图片显示尺寸(如100vw表示视口宽度)。- 实现代码:
<img src="low-res-image.jpg" srcset="high-res-image.jpg 1920w, low-res-image.jpg 1024w" sizes="(min-width: 1200px) 1920px, 100vw" alt="Responsive Image" /> - 浏览器行为:
- 浏览器根据当前视口宽度匹配
sizes中的条件。 - 从
srcset中选择最合适的图片加载(优先高分辨率设备)。
- 浏览器根据当前视口宽度匹配
2. 与懒加载结合的优化
- 动态加载响应式图片:
在懒加载中,将data-original替换为完整的srcset和sizes:在<img src="low-res-image.jpg" data-srcset="high-res-image.jpg 1920w, low-res-image.jpg 1024w" data-sizes="(min-width: 1200px) 1920px, 100vw" lazyload="true" />IntersectionObserver回调中动态赋值:img.srcset = img.dataset.srcset; img.sizes = img.dataset.sizes;
3. 优势与注意事项
- 优势:
- 避免大图在小屏设备上浪费带宽。
- 提升加载速度和用户体验(如移动端首屏秒开)。
- 注意事项:
- 确保
srcset中的图片已通过 CDN 优化。 - 使用
picture标签支持 WebP 等现代格式:<picture> <source srcset="image.webp" type="image/webp"> <img src="image.jpg" alt="WebP Support"> </picture>
- 确保
4.5 综合优化建议
- 组合策略:
- 占位图 +
Intersection Observer+srcset可覆盖性能、兼容性和响应式需求。
- 占位图 +
- 动态内容处理:
- 对于无限滚动或动态加载的内容,需在新增元素后重新绑定
IntersectionObserver。
- 对于无限滚动或动态加载的内容,需在新增元素后重新绑定
- 工具辅助:
- 使用 Lighthouse 工具分析图片加载性能,优化加载优先级。
通过以上策略,可显著提升网页的加载性能,同时兼顾用户体验和开发效率。
五、技术的实际应用场景
5.1 电商网站
- 商品列表页:用户滚动页面时,商品图片逐行加载,避免一次性加载所有商品图片。
- 详情页:图片轮播图和商品详情图使用懒加载,提升页面打开速度。
5.2 新闻门户
- 文章列表:长列表中的图片懒加载,减少首屏加载时间。
- 图片新闻:多张图片的新闻页面,用户滚动时逐步加载图片。
5.3 社交媒体
- 动态流:用户滚动时加载动态流中的图片和视频,避免页面卡顿。
六、总结
图片懒加载是提升网页性能的重要手段,其核心在于按需加载和延迟加载,通过合理使用 data-original 属性、getBoundingClientRect() 方法以及现代的 Intersection Observer API,开发者可以显著优化页面加载速度和用户体验。
本文均为作者个人理解,如果发现内容有误,欢迎各位读者在评论区指正。
最后,创作不易,要是觉得这篇文章对你有所帮助,不妨动动小手,点赞 + 收藏 !🌟