混合延迟加载:向原生延迟加载的渐进式迁移
已发表: 2022-03-10在过去的几周里,您可能听说过或读到过原生延迟加载,它将在接下来的几个月中加入 Chromium 75。
“是的,好消息,但我们必须等到所有浏览器都支持它。”
如果这是您首先想到的,请继续阅读。 我会试着说服你相反的。
让我们从原生延迟加载和优秀的 JavaScript 驱动的比较开始。
本机与 JavaScript 驱动的延迟加载
延迟加载是一种提高网站或 Web 应用程序性能的方法,它通过延迟首屏内容的加载来最大化首屏图像和 iframe(有时是视频)的渲染速度。
JavaScript 驱动的延迟加载
为了延迟加载图像或 iframe,通过将适当的src
属性替换为类似的数据属性data-src
来标记它们是一种非常常见的做法,然后依靠 JavaScript 解决方案来检测图像/iframe 何时获取靠近网站的可见部分(通常是因为用户向下滚动)并将数据属性复制到适当的属性中,然后触发其内容的延迟加载。
<img data-src="turtle.jpg" alt="Lazy turtle" class="lazy">
本机延迟加载
根据本机延迟加载规范(仍在开发中),如果您想使用本机延迟加载功能延迟加载图像或 iframe,您只需在相关标签上添加loading=lazy
属性。
<img src="turtle.jpg" alt="Lazy turtle" loading="lazy">
Addy Osmani 在他的文章“Native Image Lazy-Loading For The Web!”中广泛地讨论了这个主题。 他在其中表示,谷歌 Chrome 团队已经在开发该功能,并打算在 Chrome 75 中发布。
其他基于 Chromium 的浏览器(如 Opera 和 Microsoft Edge)也将从这一开发中受益,因为它们在基于 Chromium 75 的第一次更新中获得了相同的功能。
开始使用本机延迟加载
如果您的网站的图像在页面登陆时一次下载而没有延迟加载,您可以在您的网站中启用(在支持的情况下)本机延迟加载,就像添加 HTML 属性一样容易。 loading
属性告诉浏览器哪些图像需要立即加载,哪些可以在用户向下滚动时延迟下载。 相同的属性可以应用于 iframe。
为了告诉浏览器一个特定的图像很重要,以便他们可以尽快加载它,您必须在img
标签上添加loading="eager"
属性。 最佳做法是对主图像执行此操作——通常是对将显示在首屏的图像。
<img src="rabbit.jpg" alt="Fast rabbit" loading="eager">
要告诉浏览器应该延迟下载图像,只需添加loading="lazy"
属性。 仅当您只对次要图像执行此操作时,这才是最佳实践——通常是那些将显示在首屏下方的图像。
<img src="turtle.jpg" alt="Lazy turtle" loading="lazy">
只需将loading
属性添加到您的图像和 iframe,您就可以让您的网站使用本机延迟加载作为渐进式增强。 随着大多数现代浏览器为您的用户提供支持,您的网站将逐渐从中受益。
如果您的网站今天没有使用任何类型的延迟加载,这是最好的方法,但如果您已经实现了 JavaScript 驱动的延迟加载解决方案,您可能希望保留它,同时逐步切换到本机延迟加载。
理想的解决方案是立即开始使用本机延迟加载,并使用 polyfill 使其适用于所有浏览器。 不幸的是,原生延迟加载不是我们可以用 JavaScript 进行 polyfill 的功能。
不使用 Polyfill
当一种新的浏览器技术发布到单个浏览器时,开源社区通常会发布一个 JavaScript polyfill 来为其余浏览器提供相同的技术。 例如, IntersectionObserver
polyfill 使用 JavaScript 和 DOM 元素来协调Element.getBoundingClientRect()
以重现原生 API 的行为。
但是本机延迟加载的情况不同,因为用于loading="lazy"
的 JavaScript polyfill 必须阻止浏览器在图像或 iframe 的标记中找到 URL 时立即加载内容。 JavaScript 无法控制页面渲染的初始阶段,因此无法填充原生延迟加载。
混合延迟加载
如果您对仅将本机延迟加载作为渐进式增强不满意,或者您已经实现了基于 JavaScript 的延迟加载并且不想在不太现代的浏览器中失去此功能(但仍希望在浏览器上启用本机延迟加载支持它),那么你需要一个不同的解决方案。 介绍:混合延迟加载。
混合延迟加载是一种在支持它的浏览器上使用本机延迟加载的技术,否则依赖 JavaScript 来处理延迟加载。
“
为了进行混合延迟加载,您需要使用data
属性而不是真实的属性来标记您的延迟内容(例如在 JavaScript 驱动的延迟加载中),并添加loading="lazy"
属性。
<img data-src="turtle.jpg" loading="lazy" alt="Lazy turtle">
然后你需要一些 JavaScript。 首先,你需要检测浏览器是否支持原生延迟加载。 然后,对每个具有loading="lazy"
属性的元素执行以下操作之一:
- 如果支持原生延迟加载,则将
data-src
属性值复制到src
属性中; - 如果不支持,请在元素进入视口时初始化 JavaScript 延迟加载脚本或插件以执行此操作。
自己编写执行这些操作所需的 JavaScript 代码并不难。 您可以检测条件是否支持本机延迟加载:
if ('loading' in HTMLImageElement.prototype)
如果是,只需从data-src
复制src
属性值。 如果不是,请初始化您选择的一些延迟加载脚本。
这是执行此操作的代码片段。
<!-- In-viewport images should be loaded normally, or eagerly --> <img src="important.jpg" loading="eager" alt="Important image"> <!-- Let's lazy-load the rest of these images --> <img data-src="lazy1.jpg" loading="lazy" alt="Lazy image 1"> <img data-src="lazy2.jpg" loading="lazy" alt="Lazy image 2"> <img data-src="lazy3.jpg" loading="lazy" alt="Lazy image 3"> <script> (function() { if ("loading" in HTMLImageElement.prototype) { var lazyEls = document.querySelectorAll("[loading=lazy]"); lazyEls.forEach(function(lazyEl) { lazyEl.setAttribute( "src", lazyEl.getAttribute("data-src") ); }); } else { // Dynamically include a lazy loading library of your choice // Here including vanilla-lazyload var script = document.createElement("script"); script.async = true; script.src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/lazyload.min.js"; window.lazyLoadOptions = { elements_selector: "[loading=lazy]" //eventually more options here }; document.body.appendChild(script); } })(); </script>
你可以在这个现场演示中找到并测试上面的代码。
尽管如此,这是一个非常基本的脚本,当您使用其他属性或标签来获取响应式图像(例如srcset
和sizes
属性,甚至是picture
和source
标签)时,事情可能会变得复杂。
一点第三方帮助
在过去的四年里,我一直在维护一个名为“ vanilla-lazyload
”的开源延迟加载脚本,在 Addy Osmani 写了关于原生延迟加载的几天后,社区的反应是问我的脚本是否可以充当 polyfill。
正如我之前解释的,你不能为原生延迟加载功能创建一个 polyfill,但是,我想到了一个解决方案,它可以让开发人员更容易开始过渡到原生延迟加载,而无需编写任何 JavaScript 代码我之前提过。
从vanilla-lazyload
版本 12 开始,您只需将use_native
选项设置为true
即可启用混合延迟加载。 该脚本压缩后只有 2.0 kB,并且已经在 GitHub、npm 和 jsDelivr 上可用。
- 在 GitHub 上了解
vanilla-lazyload
演示
您现在可以通过下载 Chrome Canary 或 Microsoft Edge Insider(开发频道)然后启用“启用延迟图像加载”和“启用延迟帧加载”标志来开始使用本机延迟加载。 要启用这些标志,请在浏览器的 URL 字段中输入about:flags
并在搜索框中搜索“lazy”。
原生延迟加载演示
要分析原生延迟加载在开发者工具中的工作原理,您可以从以下演示开始。 在这一节中,没有使用任何一行 JavaScript 。 是的,这只是完全普通的原生延迟加载。
- 测试原生延迟加载演示
预期结果:一次获取所有图像,但具有不同的 HTTP 响应。 带有响应代码200
的那些是急切加载的图像,而带有响应代码206
的那些只是为了获取有关图像的初始信息而被部分获取。 然后,当您向下滚动时,将使用200
响应代码完全获取这些图像。
混合延迟加载演示
要分析混合延迟加载的工作原理,您可以开始玩下一个演示。 这里使用[email protected]
并且use_native
选项设置为true
:
- 测试混合延迟加载演示
期待什么:在不同的浏览器上尝试演示,看看它的表现如何。 在支持本机延迟加载的浏览器上,该行为与本机延迟加载演示中的行为相同。 在不支持本机延迟加载的浏览器上,图像将在您向下滚动时下载。
请注意vanilla-lazyload
在后台使用 IntersectionObserver API,因此您需要在 Internet Explorer 和较新版本的 Safari 上填充它。 不过,如果不提供 polyfill 也没什么大不了的,因为在这种情况下vanilla-lazyload
只会一次下载所有图像。
注意:在vanilla-lazyload
的自述文件的“To Polyfill or Not To Polyfill”章节中阅读更多内容。
在您的网站中尝试混合延迟加载
由于本机延迟加载即将在某些浏览器中出现,您今天为什么不给它一个使用混合延迟加载的机会呢? 这是您需要做的:
HTML 标记
最简单的图像标记由两个属性组成: src
和alt
。
对于首屏图像,您应该保留src
属性并添加loading="eager"
属性。
<img src="important.jpg" loading="eager" alt="Important image">
对于首屏图像,您应该将src
属性替换为数据属性data-src
并添加loading="lazy"
属性。
<img data-src="lazy.jpg" loading="lazy" alt="A lazy image">
如果您想使用响应式图像,请对srcset
和sizes
属性执行相同操作。
<img alt="A lazy image" loading="lazy" data-src="lazy.jpg">
如果您更喜欢使用picture
标签,请同时更改source
标签中的srcset
、 sizes
和src
。
<picture> <source media="(min-width: 1200px)"> <source media="(min-width: 800px)"> <img alt="A lazy image" loading="lazy" data-src="lazy.jpg"> </picture>
picture
标签还可用于选择性地为您的图像加载 WebP 格式。
注意:如果您想了解vanilla-lazyload
的更多用法,请阅读其自述文件的“入门”HTML 部分。
JavaScript 代码
首先,您需要在您的网站上包含vanilla-lazyload
。
你可以从像 jsDelivr 这样的 CDN 加载它:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/lazyload.min.js"></script>
或者你可以使用 npm 安装它:
npm install vanilla-lazyload@12
也可以使用带有自动初始化的async
脚本; 使用type="module"
将其加载为 ES 模块或使用 RequireJS 将其加载为 AMD。 在自述文件的“入门”脚本部分中找到更多包含和使用vanilla-lazyload
的方法。
然后,在您的网站/Web 应用程序的 JavaScript 代码中,包括以下内容:
var pageLazyLoad = new LazyLoad({ elements_selector: "[loading=lazy]", use_native: true // ← enables hybrid lazy loading });
注意:脚本有很多其他设置可以用来自定义vanilla-lazyload
的行为,例如增加滚动区域的距离,从该区域开始加载元素或仅在元素停留在视口中时才加载元素给定的时间。 在自述文件的 API 部分查找更多设置。
一起使用async
脚本
要将它们放在一起并使用async
脚本来最大化性能,请参考以下 HTML 和 JavaScript 代码:
<!-- In-viewport images should be loaded normally, or eagerly --> <img src="important.jpg" loading="eager" alt="Important image"> <!-- Let's lazy-load the rest of these images --> <img data-src="lazy1.jpg" loading="lazy" alt="Lazy image 1"> <img data-src="lazy2.jpg" loading="lazy" alt="Lazy image 2"> <img data-src="lazy3.jpg" loading="lazy" alt="Lazy image 3"> <!-- Set the options for the global instance of vanilla-lazyload --> <script> window.lazyLoadOptions = { elements_selector: "[loading=lazy]", use_native: true // ← enables hybrid lazy loading }; </script> <!-- Include vanilla lazyload 12 through an async script --> <script async src="https://cdn.jsdelivr.net/npm/[email protected]/dist/lazyload.min.js"></script>
而已! 通过这些非常简单的步骤,您将在您的网站中启用混合延迟加载!
重要的最佳实践
- 仅将延迟加载应用于您知道可能会显示在首屏下方的图像。 急切地加载首屏以最大限度地提高性能。 如果您只是对页面中的所有图像应用延迟加载,则会降低渲染性能。
- 在加载图像之前,使用 CSS 为图像保留一些空间。 这样,他们将推送下面的其余内容。 如果您不这样做,则更多的图像将在它们应该被放置在首屏之前,从而触发它们的立即下载。 如果你需要一个 CSS 技巧来做到这一点,你可以在
vanilla-lazyload
自述文件的提示和技巧部分找到一个。
优点和缺点
本机延迟加载 | |
---|---|
优点 |
|
缺点 |
|
JAVASCRIPT 驱动的延迟加载 | |
---|---|
优点 |
|
缺点 |
|
混合延迟加载 | |
---|---|
优点 |
|
缺点 |
|
包起来
我很高兴原生延迟加载即将出现在浏览器中,我迫不及待地等待所有浏览器供应商实现它!
同时,您可以选择丰富您的 HTML 标记以进行渐进式增强并仅在支持的情况下获取本机延迟加载,或者您可以选择混合延迟加载并获取本机和 JavaScript 驱动的延迟加载,直到本机延迟加载的那一天绝大多数浏览器都支持。
试一试! 不要忘记在 GitHub 上加注星标/观看vanilla-lazyload
,并在评论部分告诉我你的想法。
关于 SmashingMag 的进一步阅读:
- 现在你看到我了:如何延迟、延迟加载和使用 IntersectionObserver 采取行动
- 使用 ConditionerJS 延迟加载 JavaScript 模块
- 2019 年前端性能检查表(PDF、Apple Pages、MS Word)
- 提高网站性能如何帮助拯救地球