懒加载图片以获取最佳性能的最佳方案
图片懒加载是一个很受欢迎的优化站点的方法,因为它很容易实现,并且能明显提升性能。使用惰性加载,我们可以异步加载图片,这意味着可以只加载浏览器视口内的图片。 大约一年前,图像和iframe
的原生惰性加载特性已发布,但是仅针对谷歌和其他主流浏览器。该功能的重点是使浏览器可以控制何时请求图像或iframe
资源,这使得开发工作更加容易。在此前,唯一的选择是使用JavaScript
插件来监视视口更改并动态加载资源。现在,浏览器也可以原生支持(懒加载)。
在写此文时候(原文在dev.to上是2020年8月31日发布),大约73% of currently used browsers支持这个特性,这还不赖。但是,我们不想让27%
的潜在用户无法访问和使用网站的图片资源。
所以,这就很有趣了,值得思考:
- 对于支持原生懒加载特性的浏览器,我们想直接使用它
- 对于不支持原生懒加载特性的浏览器,我们使用
JS
插件 - 根据浏览器对原生懒加载特性支持与否,考虑是否引入
JS
插件 - 必须同时支持
img
和source
元素
loading 属性
loading
属性有三个值。
-
auto
- 默认值。和不设置loading
属性效果一样。 -
eager
- 立即加载资源。 -
lazy
- 一旦资源在视口就加载它
尽管上面的取值有特定的使用案例,但是,我们通常希望对折叠以上(视口)的资源使用eager
,对折叠以下的资源使用lazy
。
现代的方法
我们需要编写一个脚本,该脚本将在HTML
文档后运行。我们使用了Jekyll
,并将脚本作为HTML
的部分添加在body
的末尾。这是运行JavaScript
函数以避免渲染阻塞的最有效方法。
标记图片
我们希望JavaScript
函数基于浏览器原生支持的特性来开启图像加载过程。为此,我们将图像的路径添加到data-src
而不是src
。但是我们不应该将src
留空,因此我们将使用1 x 1px
透明图像占位符。我们对img
元素标记如下所示:
<img
src="/path/to/placeholder/image.png"
data-src="/path/to/full/image.jpg"
alt="Image description"
class="lazyload"
loading="lazy"
/>
复制代码
⚠️
class="lazyload"
是给懒加载后备插件使用的。我使用了此特定类名的插件lazysizes
另外,我们想支持picture
元素,它包含多个source
元素并且img
元素作为后备元素。
<picture>
<source data-srcset="path/to/image.webp" type="image/webp" />
<source data-srcset="path/to/image.jpg" />
<img loading="lazy"
class="lazyload"
src="path/to/placeholder/image.png"
data-src="path/to/image.jpg"
alt="Image description"
/>
picture>
复制代码
特性检测
我们需要检测用户的浏览器是否支持原生的懒加载。幸运的是,我们可以直接使用JavaScript
去做这件事。
if ("loading" in HTMLImageElement.prototype) {
/* Native lazy loading is supported */
} else {
/* Native lazy loading is not supported */
}
最终JavaScript代码
对于原生懒加载,我们只需要对img
分配data-src
值给src
值,对source
分配data-srcset
值给srcset
值,剩下的事情就交给浏览器了。
对于不支持该特性的浏览器,我们只需要加载相关的JavaScript
插件,可选的,如果没有自动化集成的,那么就运行该插件。我习惯使用lazysizes,但是任何懒加载插件都会生效,前提是保证元素的标记要正确(比如类名,data元素等)。
于是,最终的JavaScript
的代码会看起来长这样:
<span class="hljs-keyword">if</span> (<span class="hljs-string">"loading"</span> <span class="hljs-keyword">in</span> HTMLImageElement.prototype) {
<span class="hljs-keyword">var</span> images = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'img[loading="lazy"]'</span>);
<span class="hljs-keyword">var</span> sources = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"source[data-srcset]"</span>);
sources.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">source</span>) </span>{
source.srcset = source.dataset.srcset;
});
images.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">img</span>) </span>{
img.src = img.dataset.src;
});
} <span class="hljs-keyword">else</span> {
<span class="hljs-keyword">var</span> script = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"script"</span>);
script.src = <span class="hljs-string">"/link/to/lazyload.js"</span>;
<span class="hljs-built_in">document</span>.body.appendChild(script);
}
本文截取Best way to lazy load images for maximum performance部分翻译,进行学习和总结。懒加载在商城站点和运营活动的场景使用更加频繁,当然,图片还要进行最优压缩、切割和CDN处理等。更多博文内容详见Jimmy Blog
- 分钟学会正则表达式(译)
- TensorFlow从0到1 | 第十一章 74行Python实现手写体数字识别
- 让浏览器不再显示 https 页面中的 http 请求警报
- 跨域访问和防盗链基本原理
- 【翻译】MongoDB指南/CRUD操作(一)
- 【直播】我的基因组50:从测序深度和位点间距来看SNV分布情况
- 【翻译】MongoDB指南/CRUD操作(二)
- 【翻译】MongoDB指南/CRUD操作(三)
- 为什么 Laravel 会成为最成功的 PHP 框架?
- 【生信菜鸟经】如何系统入门Perl
- 【翻译】MongoDB指南/CRUD操作(四)
- R包终极解决方案
- Table被web编程弃用的原因
- Web安全实战
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- swoole深入学习 2. tcp Server和tcp Client
- 一切皆Socket
- Go代码重构:23倍的性能爆增
- 分布式系统的一致性协议之 2PC 和 3PC
- Docker快速搭建WordPress博客网站
- Elasticsearch入门,这一篇就够了
- 玩转 lua in Redis
- 用docker快速搭建wordpress博客
- 生产环境优雅的重启基于Nginx、Tornado的Web服务进程
- nginx记录post body/payload数据 日志用打印出结果
- nginx的location、rewrite玩法详解
- Redis Lua脚本调试
- 安装elasticsearch 5.x, 6.x 常见问题(坑)的解决
- 轻松搞懂elasticsearch概念
- 深入Golang调度器之GMP模型