让图片学会“等你看到再出场”——懒加载全攻略
图片懒加载全解析从传统 Scroll 到现代 IntersectionObserver在前端开发的世界里性能优化永远是绕不开的核心话题✨。尤其是在电商、资讯、社交这类图片密集型的页面中大量图片的加载往往会成为页面性能的 “绊脚石”—— 首屏加载慢吞吞用户没耐心直接离开非可视区域的图片白白消耗带宽服务器压力也徒增。而图片懒加载Lazy Load作为前端性能优化的 “明星方案”正是为解决这些痛点而生。今天我们就从概念、原理到实战全方位拆解图片懒加载的实现逻辑对比传统与现代方案的优劣让你彻底吃透这个高频考点一、什么是图片懒加载图片懒加载本质是一种 “按需加载” 的资源加载策略浏览器解析页面时不会一次性加载所有img标签对应的图片而是先加载首屏可视区域内的图片当用户滚动页面使原本隐藏在视口外的图片进入可视区域Viewport时再触发这些图片的真实加载。核心实现逻辑的关键是 “资源延迟绑定”将图片的真实地址暂存到data-src自定义属性中而非直接赋值给src属性src先指向体积极小的占位图如 1x1 透明图只有满足 “进入视口” 条件时才把data-src的值替换到src中触发真实的图片 HTTP 请求。二、为什么需要图片懒加载没有懒加载的页面浏览器解析img标签时只要看到src属性就会立刻发起请求这会带来两个致命问题首屏加载速度慢首页的所有图片请求会和 HTML、CSS、JS 的加载 “抢占” 网络资源导致首屏 HTML 渲染、样式加载被阻塞用户面对空白页面的等待时间变长数据显示首屏加载超过 3 秒用户流失率超 50%。无效请求浪费视口之外的图片如下滚才能看到的列表项加载后用户可能永远不会滚动到对应位置既浪费了用户的移动带宽尤其是移动端也增加了服务器的并发压力。而懒加载的引入恰好解决了这些问题✅ 提升用户体验首屏内容快速渲染用户无需长时间等待✅ 节省带宽资源仅加载用户能看到的图片减少无效请求✅ 降低服务器压力分散图片请求的时间和并发量避免瞬间高并发。三、图片懒加载的解决方案核心所有懒加载方案都围绕两个核心原则展开缺一不可1. 首屏优先暂时不需要加载的图片src属性先指向小体积占位图如 1x1 透明图、加载中占位图让浏览器优先加载 HTML、CSS、JS 等核心资源保证首屏内容快速呈现。2. 按需加载通过监听页面滚动或原生 API 监听交集状态实时判断图片是否进入视口只有当图片进入视口时才将data-src中的真实地址赋值给src触发真实图片的加载。四、如何实现图片懒加载️接下来我们从代码层面拆解传统方案和现代方案的实现逻辑对比两者的优劣。1. 传统方案监听滚动事件onscroll 节流这是早期懒加载的主流实现方式核心是 “监听滚动 节流控制 手动计算位置”。1.1 核心思路① 图片预处理给非首屏图片添加lazy类src赋值占位图真实地址存在data-src自定义属性中② 节流控制给scroll事件绑定节流函数避免高频触发导致性能卡顿③ 视口判断滚动时遍历所有lazy图片通过getBoundingClientRect()计算图片与视口的位置关系判断是否进入视口④ 加载图片若图片进入视口将data-src赋值给src移除lazy类、添加loaded类用于样式过渡并移除data-src属性⑤ 初始化检查页面加载完成后先执行一次懒加载判断避免首屏内的lazy图片未加载。1.2 代码javascript// 节流函数控制函数高频触发避免滚动时性能卡顿 function throttle(func, wait) { let timeout null; // 定时器标识用于控制执行时机 return function () { if (!timeout) { // 若定时器不存在说明可以执行函数 timeout setTimeout(() { func.apply(this, arguments); // 执行目标函数保留this和参数 timeout null; // 执行完成后重置定时器 }, wait); } }; } function lazyLoad() { const lazyImages document.querySelectorAll(img.lazy); // 获取所有待加载的图片 const windowHeight window.innerHeight; // 获取视口高度 lazyImages.forEach(img { // 跳过已加载的图片已移除lazy类 if (!img.classList.contains(lazy)) return; const rect img.getBoundingClientRect(); // 获取图片的位置信息相对于视口 // 核心判断图片顶部进入视口下方且底部未完全离开视口上方 → 图片进入视口 if (rect.top windowHeight rect.bottom 0) { if (img.dataset.src) { console.log(Loading image via Scroll:, img.dataset.src); img.src img.dataset.src; // 替换src触发真实图片加载 img.removeAttribute(data-src); // 移除自定义属性避免重复加载 img.classList.remove(lazy); // 移除lazy类标记为已加载 img.classList.add(loaded); // 添加loaded类实现透明度过渡 } } }); } // 节流处理懒加载函数200ms执行一次 const throttledLazyLoad throttle(lazyLoad, 200); // 监听滚动事件触发节流后的懒加载 document.addEventListener(scroll, throttledLazyLoad); // 窗口大小变化时重新判断图片位置 window.addEventListener(resize, throttledLazyLoad); // 页面加载完成后初始化检查首屏图片 document.addEventListener(DOMContentLoaded, lazyLoad);1.3 代码实现效果观察界面滚动图片变化与控制台打印1.4 该方案的缺点❌ 性能损耗即使加了节流scroll事件仍会高频触发存在一定的性能开销❌ 代码冗余需要手动计算元素与视口的位置关系逻辑易出错维护成本高❌ 适配性差在移动端、嵌套滚动等复杂布局中位置计算容易失效适配成本高。1.5 关键 API 解析throttle (func, wait)自定义节流函数控制高频事件触发频率避免性能卡顿。func需要被节流的目标函数此处为lazyLoadwait节流等待时间毫秒此处为 200ms即函数每 200ms 最多执行一次document.querySelectorAll (img.lazy)根据CSS选择器获取所有带lazy类的待加载图片返回NodeList集合。window.innerHeight获取当前浏览器视口的高度用于判断图片是否进入视口。Element.classList.contains (lazy)布尔值判断图片元素是否包含lazy类跳过已加载的图片。Element.getBoundingClientRect ()获取元素相对于视口的位置信息返回DOMRect对象包含top元素顶部距视口顶部距离、bottom元素底部距视口顶部距离等属性。img.removeAttribute (data-src)移除图片的data-src属性避免重复读取。Element.classList.remove (lazy)移除图片的lazy类标记为已加载。Element.classList.add (loaded)为图片添加loaded类实现加载后的样式过渡。document.addEventListener (scroll, throttledLazyLoad)监听页面滚动事件触发节流后的懒加载函数。window.addEventListener (resize, throttledLazyLoad)监听窗口大小变化事件重新判断图片位置适配视口尺寸变化。document.addEventListener (DOMContentLoaded, lazyLoad)监听DOM加载完成事件初始化执行懒加载函数检查首屏图片是否需要加载。2. 现代方案IntersectionObserver推荐为了解决传统方案的痛点浏览器原生提供了IntersectionObserverAPI交集观察器专门用于监听 “元素是否进入视口 / 与其他元素产生交集”是目前懒加载的最优解。2.1 核心思路① 浏览器原生支持无需手动监听scroll、resize等事件由浏览器底层优化执行逻辑② 交集监听创建IntersectionObserver实例指定观察的目标元素lazy图片③ 自动判断当目标元素与视口产生交集满足阈值条件时触发回调函数④ 加载图片在回调中替换data-src到src移除lazy类停止观察该元素避免重复触发⑤ 降级处理若浏览器不支持该 API直接加载所有图片保证功能可用。2.2 代码javascriptdocument.addEventListener(DOMContentLoaded, function() { const lazyImages document.querySelectorAll(img.lazy); // 获取所有待加载图片 // 检查浏览器是否支持IntersectionObserver if (IntersectionObserver in window) { // 创建交集观察器实例 const imageObserver new IntersectionObserver(function(entries, observer) { // 遍历所有被观察的元素的交集状态 entries.forEach(function(entry) { // entry.isIntersecting元素是否进入视口产生交集 if (entry.isIntersecting) { const img entry.target; // 获取当前触发的图片元素 console.log(Loading image via IntersectionObserver:, img.dataset.src); img.src img.dataset.src; // 替换src加载真实图片 img.classList.remove(lazy); // 标记为已加载 img.classList.add(loaded); // 添加样式过渡类 observer.unobserve(img); // 停止观察该图片避免重复触发 } }); }, { root: null, // 观察的根元素null表示视口 rootMargin: 0px, // 根元素的边距扩展/缩小观察区域 threshold: 0.1 // 阈值图片10%可见时触发回调 }); // 遍历所有lazy图片开始观察 lazyImages.forEach(function(image) { imageObserver.observe(image); }); } else { // 降级处理不支持时直接加载所有图片 console.log(IntersectionObserver not supported, loading all images.); lazyImages.forEach(function(img) { img.src img.dataset.src; img.classList.remove(lazy); img.classList.add(loaded); }); } });2.3 代码实现效果观察界面滚动图片变化与控制台打印2.4 该方案的优势✅ 无性能损耗浏览器底层实现无需手动节流 / 防抖性能远超scroll监听✅ 代码简洁无需手动计算元素位置逻辑清晰维护成本低✅ 适配性强完美兼容移动端、嵌套滚动等复杂布局✅ 可扩展支持自定义观察规则如rootMargin扩展观察区域、threshold调整触发阈值。2.5 关键 API 解析IntersectionObserver(callback, options)构造函数创建交集观察器实例。callback交集状态变化时的回调函数接收两个参数entries数组每个元素是IntersectionObserverEntry对象包含元素的交集状态、位置等信息observer当前的IntersectionObserver实例。options配置项可选root观察的根元素默认null视口rootMargin根元素的边距格式同 CSS margin如 “100px 0”可扩展 / 缩小观察区域threshold触发回调的阈值0~10 表示元素刚进入视口就触发1 表示元素完全进入视口才触发。entry.isIntersecting布尔值判断元素是否与根元素产生交集进入视口。observer.observe(target)开始观察指定的目标元素。observer.unobserve(target)停止观察指定的目标元素。五、CSS 与 HTML 代码CSSstyle /* 页面基础样式 */ body { font-family: Arial, sans-serif; margin: 0; padding: 0; text-align: center; } /* * 空白间隔区样式 * 用于撑开页面高度模拟长页面滚动效果 */ .spacer { height: 150vh; /* 核心高度设置为 1.5 倍视口高度 (150vh) */ display: flex; flex-direction: column; align-items: center; justify-content: flex-start; /* 内容从顶部开始排列 */ padding-top: 50vh; /* 核心提示词距离顶部 1/3 (50vh / 150vh ≈ 0.33) */ box-sizing: border-box; background-color: #f9f9f9; border-bottom: 1px solid #ddd; } /* 图片容器样式 */ .image-wrapper { padding: 50px 0; background-color: #fff; min-height: 400px; /* 最小高度防止图片加载前高度塌陷 */ display: flex; align-items: center; justify-content: center; } /* * 懒加载图片样式 * .lazy 类表示图片尚未加载 */ img.lazy { max-width: 80%; height: auto; display: block; margin: 0 auto; opacity: 0.3; /* 初始低透明度显示占位效果 */ transition: opacity 0.5s; /* 添加过渡效果使加载更平滑 */ } /* * 图片加载完成后的样式 * .loaded 类在 JS 中加载完成后添加 */ img.loaded { opacity: 1; /* 恢复完全不透明 */ } h1, h2 { color: #333; } /styleHTMLbody !-- 第一部分首屏空白区 作用展示标题和提示迫使用户向下滚动 -- div classspacer h1传统懒加载方案/h1 h2⬇️ 向下滑动加载第一张图片 ⬇️/h2 /div !-- 第二部分第一张图片 >六、面试官会问图片懒加载的核心原理是什么答核心是 “按需加载”将非首屏图片的真实地址存到data-src自定义属性src指向占位图通过监听滚动传统或IntersectionObserver现代判断图片是否进入视口进入后将data-src赋值给src触发真实图片加载。传统懒加载方案中为什么要使用节流函数答scroll事件会在滚动过程中高频触发每秒数十次若直接执行懒加载逻辑会导致大量 DOM 操作和计算引发页面卡顿节流函数能控制函数在指定时间内只执行一次减少性能损耗。IntersectionObserver 相比传统 scroll 方案有哪些优势答① 性能更好浏览器底层优化无需手动节流② 代码更简洁无需手动计算元素位置③ 适配性强兼容复杂布局④ 可扩展支持自定义观察规则。如何判断一个元素是否进入视口答传统方案用element.getBoundingClientRect()获取元素的位置信息判断rect.top window.innerHeight rect.bottom 0现代方案直接通过IntersectionObserver的isIntersecting属性判断。懒加载的降级方案是什么答若浏览器不支持IntersectionObserver如部分老旧浏览器直接遍历所有lazy图片将data-src赋值给src保证图片能正常加载。七、结语图片懒加载作为前端性能优化的 “基础操作”其核心始终是 “按需加载”—— 优先保证首屏体验减少无效资源消耗。传统的scroll节流方案兼容旧浏览器但存在性能和适配痛点而IntersectionObserver作为现代方案凭借浏览器原生优化、简洁的代码逻辑成为当前懒加载的首选。在实际开发中我们需要根据项目的兼容需求选择方案若需兼容老旧浏览器可采用 “IntersectionObserverscroll 降级” 的混合方案若面向现代浏览器直接使用IntersectionObserver即可。性能优化没有银弹但图片懒加载是列表类页面电商、资讯、社交的 “必做优化”小小的改动就能显著提升页面加载速度和用户体验。希望这篇文章能帮你彻底吃透图片懒加载无论是面试还是实战都能游刃有余

相关新闻

大数据领域数据中台的安全架构设计

大数据领域数据中台的安全架构设计

大数据领域数据中台的安全架构设计 关键词:数据中台、安全架构、数据安全、隐私保护、访问控制、加密技术、安全审计 摘要:本文深入探讨大数据领域数据中台的安全架构设计。我们将从数据中台的基本概念出发,详细分析其面临的安全挑战,提出多层次的安全防护架构,并深入讲解…

2026/7/3 15:47:22 阅读更多 →
2026降AIGC必备技巧,还有免费ai查重福利!这3款工具降AI工具一键解决你的烦恼【建议收藏】

2026降AIGC必备技巧,还有免费ai查重福利!这3款工具降AI工具一键解决你的烦恼【建议收藏】

明明是一个字一个字敲上去得,结果查重报告出来的时候,看着92%的AIGC疑似度,我整个人都裂开了。 导师直接在群里说:“AI率超过30%的直接延毕。”当时我真的急得像热锅上的蚂蚁。 为了保住学位证,我这几试了十几种方法…

2026/7/5 10:54:42 阅读更多 →
寒假集训5——二分

寒假集训5——二分

这三题我都超时了,优化完可能会再上传。这些都不是AC代码,请批判性查阅,轻喷!!! 1.B2166 查找不重复元素出现的位置 题目描述 输入 n 个不超过 109 的严格递增的正整数组成的数列 a1​,a2​,…,an​&…

2026/7/3 4:46:02 阅读更多 →

最新新闻

SONiC 2024 容器化架构解析:10个核心Docker容器如何驱动网络转发

SONiC 2024 容器化架构解析:10个核心Docker容器如何驱动网络转发

SONiC 2024容器化架构深度解析:10个核心容器如何构建下一代云网络1. 现代网络操作系统的容器化革命当微软在2016年首次开源SONiC项目时,很少有人能预料到这个基于Linux的网络操作系统会彻底改变数据中心网络的构建方式。八年后的今天,SONiC已…

2026/7/6 2:55:56 阅读更多 →
QooBot:全栈开源的仿生人操作系统——软硬一体,自由制造

QooBot:全栈开源的仿生人操作系统——软硬一体,自由制造

QooBot:全栈开源的仿生人操作系统——软硬一体,自由制造 摘要:QooBot 是一个面向仿生人的开源全栈生态,涵盖从机械图纸、电路设计到操作系统、AI 算法的完整技术栈。本文从架构全景、大脑核心、推理引擎、开发者生态等维度全面解读…

2026/7/6 2:53:55 阅读更多 →
可变级数LC无源自均压海量级联多电平拓扑机理研究——代替传统LCC/MMC的新一代特高压直流逆变架构

可变级数LC无源自均压海量级联多电平拓扑机理研究——代替传统LCC/MMC的新一代特高压直流逆变架构

可变级数LC无源自均压海量级联多电平拓扑机理研究——取代传统LCC/MMC的新一代特高压直流逆变架构 ----------作者:杨连江 摘要 针对我国特高压直流输电现有两大技术体系(LCC电网换相直流、MMC柔性直流)存在的底层机理缺陷,本文提…

2026/7/6 2:53:55 阅读更多 →
卡梅德生物技术快报| KM13 辅助噬菌体的天然 VHH 噬菌体文库全套构建流程与数据验证

卡梅德生物技术快报| KM13 辅助噬菌体的天然 VHH 噬菌体文库全套构建流程与数据验证

一、提出问题:实验室自建纳米抗体文库常遇四大工程化痛点 食品检测实验室自主构建 VHH 噬菌体文库时,普遍存在工程化落地难题:其一,普通单轮 PCR 扩增 VHH 基因存在大量缺失,文库多样性不足;其二&#xff…

2026/7/6 2:51:55 阅读更多 →
Variance Reduction with Baseline 补充 - 加基线使得方差降低

Variance Reduction with Baseline 补充 - 加基线使得方差降低

什么叫基线 基线就是一个只和当前状态s有关、和动作a无关的数值 b(s),用来做 “参考平均分”假设某状态s平均长期收益 b(s)10 某条轨迹 G_t18:A_t18-108>0,动作比平均更好,加大该动作概率 某条轨迹 G_t3:A_t3-10-7…

2026/7/6 2:51:55 阅读更多 →
MP1584 降压电源 PCB 布局 5 大要点:实测 SW 节点尖峰降低 60%

MP1584 降压电源 PCB 布局 5 大要点:实测 SW 节点尖峰降低 60%

MP1584降压电源PCB布局实战:5大核心技巧让SW节点尖峰直降60%作为一名长期奋战在电源设计一线的工程师,我深知PCB布局对开关电源性能的决定性影响。今天我们就以MP1584这款经典降压芯片为例,通过实测数据揭示那些手册上不会告诉你的布局奥秘。…

2026/7/6 2:49:55 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻