整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

手搓一个TinyPng压缩图片的WebpackPlugin

者: JowayYoung

转发链接:https://mp.weixin.qq.com/s/eqsZwZPCX-GZyB-EOm3TwQ

之前的文章中,我们讨论了图片的尺寸自适应、裁切与缩放、压缩、动态webp等技术。这些技术都是对单张图片的处理,而在实际项目中,我们往往需要处理大量的图片。本文将讨论如何高效批量优化图片,并介绍一些图片加载技巧。

一、图片预加载

图片预加载(Preloading Images)是一种提前加载即将使用的图片资源的技术。通过在页面加载时就将未来可能用到的图片资源进行预加载,可以在用户真正需要这些图片时,减少等待时间,提升用户体验。


HTML中的预加载


在HTML中,可以通过<link>标签的rel属性来实现图片预加载。例如,我们可以在页面的`<head>`标签中添加如下代码:

<link rel="preload" href="image.jpg" as="image" fetchpriority="high">


<link> 标签用于预加载一个图片资源。让我们逐个解释其中的属性及其作用:


  • rel="preload":


当前<link>标签的用途是预加载资源。preload告诉浏览器提前加载指定的资源(在这里是图片),以便在后续使用时能够更快地提供资源。这有助于提高页面的加载性能,尤其是在资源密集型的网站上。


  • href="image.jpg":


指定要预加载的资源的URL。href属性是一个URL,指向需要预加载的资源。在这个例子中,image.jpg是要预加载的图片的路径。


  • as="image":

指定预加载资源的类型。as属性告诉浏览器预加载资源的类型,以便正确地处理和优化加载过程。在这个例子中,as="image"明确了资源是一个图片。这对于浏览器优化资源加载顺序和优先级非常重要。


  • fetchpriority="high":


指定预加载资源的获取优先级。fetchpriority属性是一个新的属性,用于指示浏览器在预加载资源时的优先级。在这个例子中,fetchpriority="high"告诉浏览器这是一个高优先级的资源,应该尽快加载。这在需要确保关键资源(如首屏图片)快速加载时非常有用。


CSS中的预加载


在CSS中,可以通过background-image属性来实现图片预加载。例如,我们可以在CSS文件中添加如下代码:

.preload {
 background-image: url('image.jpg');
}

这段CSS代码定义了一个`.preload`类,其中包含了一个 background-image 属性,指定了要预加载的图片资源的URL。在页面加载时,浏览器会提前加载这个图片资源,以便在后续使用时能够更快地提供资源。


JavaScript中的预加载


JavaScript中,可以通过Image对象来实现图片预加载。例如,我们可以在JavaScript代码中添加如下代码:

var img = new Image();
img.src = 'image.jpg';

这段JavaScript代码创建了一个新的Image对象,并设置了src属性为要预加载的图片资源的URL。当这段代码执行时,浏览器会开始加载这个图片资源,以便在后续使用时能够更快地提供资源。


二、图片懒加载

图片懒加载(Lazy Loading Images)是一种延迟加载图片资源的技术。通过在页面加载时只加载可见区域内的图片资源,可以减少页面的加载时间,提升用户体验。


img loading属性


HTML中,可以通过loading属性来实现图片懒加载。例如,我们可以在<img>标签中添加如下代码:


<img src="image.jpg" loading="lazy" alt="Image">

loading属性是一个新的属性,用于指定图片的加载方式。它有三个可能的值:


  • auto: 默认值,表示图片会在页面加载时立即加载。
  • lazy: 表示图片会在视口内时才会加载。
  • eager: 表示图片会在页面加载时立即加载,不管是否在视口内。


Intersection Observer API


JavaScript中,可以通过Intersection Observer API来实现图片懒加载。Intersection Observer API是一种用于监视元素与视口交叉状态的API,可以用于实现懒加载、无限滚动等功能。


例如,我们可以在JavaScript代码中添加如下代码:

// 创建一个IntersectionObserver实例
 const intersectionObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
  if (entry.isIntersecting) {
  // 当元素与视窗交叉时执行的操作
  const img = entry.target; // entry.target是交叉的元素
  // 假设data-src属性包含了图片的路径
  img.src = img.dataset.src;
  intersectionObserver.unobserve(img); // 停止观察该元素
 }
 });
});

// 为所有需要滚动加载的元素(例如图片)设置观察
document.querySelectorAll('img[data-src]').forEach((img) => {
 intersectionObserver.observe(img);
});

这段JavaScript代码创建了一个IntersectionObserver实例,并为所有带有data-src属性的图片元素设置了观察。当图片元素与视口交叉时,会加载图片资源,并停止观察该元素。

Scroll事件


JavaScript中,也可以通过监听scroll事件来实现图片懒加载。例如,我们可以在JavaScript代码中添加如下代码:

// 获取所有带有data-src属性的图片元素
 const lazyImages = document.querySelectorAll('img[data-src]');
 // 懒加载函数
 function lazyLoad() {
  lazyImages.forEach((img) => {
  if (img.offsetTop < window.innerHeight + window.pageYOffset + 200) {
  img.src = img.dataset.src;
  img.removeAttribute('data-src');
  }
 });
 // 更新 lazyImages,排除已加载的图片
 lazyImages = document.querySelectorAll('img[data-src]');
 // 如果所有的图片都已经加载,则移除事件监听器
 if (lazyImages.length === 0) {
 document.removeEventListener('scroll', lazyLoad);
 }
}
// 监听scroll事件
document.addEventListener('scroll', lazyLoad);
// 初始检查一次,以便在页面加载时懒加载位于视窗中的图片
lazyLoad();

这段JavaScript代码监听了scroll事件,并在图片元素进入视口时加载图片资源。当图片进入视口时,会加载图片资源,并移除data-src属性。


结合多种方法来实现图片懒加载


在实际项目中,我们可以结合多种方法来实现图片懒加载,以便在不同浏览器和环境下提供最佳的用户体验。例如,我们可以先检查浏览器是否支持loading属性,如果支持,则使用`loading`属性实现图片懒加载;如果不支持,则检查浏览器是否支持Intersection Observer API,如果支持,则使用Intersection Observer API实现图片懒加载;如果不支持,则使用scroll事件实现图片懒加载。


下面是一个示例代码,演示了如何结合多种方法来实现图片懒加载:


html

<body>
 <img src="placeholder.jpg" data-src="image1.jpg" alt="Description 1">
 <img src="placeholder.jpg" data-src="image2.jpg" alt="Description 2">
 <img src="placeholder.jpg" data-src="image3.jpg" alt="Description 3">
 <!-- 更多 img -->
 <script src="lazyload.js"></script>
</body>

javascript

const lazyImages = document.querySelectorAll('img[data-src]');
// 判断浏览器是否支持 loading 属性
if('loading' in HTMLImageElement.prototype) {
  lazyImages.forEach(img => {
  img.src = img.dataset.src;
  });
 } else if('IntersectionObserver' in window) {
  // 使用Intersection Observer API实现懒加载
 const intersectionObserver = new IntersectionObserver((entries) => {
 entries.forEach(entry => {
 if (entry.isIntersecting) {
 const img = entry.target;
 img.src = img.dataset.src;
 intersectionObserver.unobserve(img);
 }
 });
 });

 lazyImages.forEach((img) => {
 intersectionObserver.observe(img);
 });
} else {
 // 使用scroll事件实现懒加载
 let lazyImages = document.querySelectorAll('img[data-src]');
 function lazyLoad() {
 lazyImages.forEach((img) => {
 if (img.offsetTop < window.innerHeight + window.pageYOffset + 200) {
 img.src = img.dataset.src;
 img.removeAttribute('data-src');
 }
 });
 lazyImages = document.querySelectorAll('img[data-src]');
 if (lazyImages.length === 0) {
 document.removeEventListener('scroll', lazyLoad);
 }
 }
 document.addEventListener('scroll', lazyLoad);
 lazyLoad();
}

三、渐进式图片加载

图片渐进式加载(Progressive Image Loading)是一种逐步加载图片资源的技术。通过在图片加载过程中逐步显示模糊的低分辨率图片,可以提升用户体验,减少等待时间。这种技术不仅适用于优化页面性能,还可以为用户提供视觉上的反馈,使页面显得更加流畅。


渐进式 JPEG


渐进式 JPEG (Progressive JPEG) 是一种通过逐步显示图片的技术,渐进式 JPEG 与标准的 JPEG 图片区别在于,渐进式 JPEG 图片在加载时会逐步显示图片的分辨率,而不是一次性显示完整的图片。这种逐步加载的方式可以提升用户体验,减少等待时间。渐进式 JPEG 图片最初会显示的是一张模糊的低分辨率图片,随着数据的不断加载,图片的分辨率会逐步提高,直至达到全分辨率。这种方法特别适合需要加载大图的场景。


许多图像编辑工具和压缩工具都支持将图片保存为渐进式 JPEG。在实际项目中,例如,在 Photoshop 中保存图片时,可以勾选“渐进式”选项。也可以使用命令行工具如ImageMagick(https://imagemagick.org/index.php)来生成渐进式 JPEG:

1convert input.jpg -interlace Plane output.jpg




需要注意的是渐进式 JPEG 图片的文件大小通常会比标准的 JPEG 图片稍大,因为渐进式 JPEG 图片包含了更多的数据,用于逐步显示图片的分辨率,但是这种额外的数据可以提升用户体验。因此,在选择使用渐进式 JPEG 图片时,需要权衡图片质量和文件大小之间的关系。


占位图技术


占位图技术(Placeholder Image)通常使用一个非常小的、模糊的低分辨率图像作为占位符,在高分辨率图像加载完成之前先显示出来。这种方法通过减少初始加载时间和网络请求,可以显著提升页面的首屏加载速度。


占位图实现原理很简单,只需要在页面中插入一个占位图像,然后在高分辨率图像加载完成后替换为真实图像即可。


  • 生成一个小尺寸的图片,并将其模糊化处理。
  • 在页面初始加载时,先显示这张模糊的小图,待高分辨率图像加载完成后再替换。


代码示例:

html:

<img src="https://fs.autohome.com.cn/energyspace_views/image_demo/compress_before.png?format=webp&dis_rule=20x0_q50_" data-src="https://fs.autohome.com.cn/energyspace_views/image_demo/compress_before.png?format=webp&dis_rule=400x0_q90_" alt="Description">

javascript:

document.addEventListener('DOMContentLoaded', function() {
  const lazyImages = document.querySelectorAll('img[data-src]');
  lazyImages.forEach(img => {
  const placeholder = new Image();
  placeholder.src = img.src;
  placeholder.onload = () => {
  img.src = img.dataset.src;
  };
  });
});



img src 属性中的图片是一个模糊的小图,data-src 属性中的图片是高分辨率图像。在页面加载时,先显示模糊的小图,待高分辨率图像加载完成后再替换。


使用占位图技术可以有效减少页面的加载时间,提升用户体验。同时,占位图技术也可以结合图片懒加载技术一起使用,进一步提升页面性能。

四、Base64 编码

在 Web 开发中,将图片转换为 Base64 编码是一种优化页面加载速度的方法,但需要权衡其优缺点。一般来说,适用于 Base64 编码的图片大小取决于几个因素,包括页面的总体加载时间、HTTP 请求的数量以及文件大小。


Base64 编码的优点


  • 减少 HTTP 请求:将图像嵌入到 HTML 或 CSS 中可以减少 HTTP 请求,从而加快页面加载速度。对于小图标或背景图片,效果尤为显著。
  • 简单易用:Base64 编码图像是一种文本格式,可以方便地嵌入 HTML、CSS 或 JSON 中,不需要额外的图像文件管理。
  • 适用于小图像:Base64 编码特别适合用于小图像,例如网站的 logo、按钮、图标等。


Base64 编码的缺点


  • 增加文件体积:Base64 编码会使文件体积增加,因此对于大图像,不推荐使用这种方法。
  • 缓存问题:由于 Base64 图像嵌入在 HTML 或 CSS 文件中,浏览器不能单独缓存这些图像文件,因此在更新图像时需要重新下载整个 HTML 或 CSS 文件。
  • 可读性差:Base64 编码图像是一长串字符,嵌入到文档中会降低文档的可读性和可维护性。


适合转为 Base64 的图片大小一般为 1KB 到 10KB 的图片:通常,文件大小在 1KB 到 10KB 之间的图片是转为 Base64 编码的最佳选择。这样的图片往往是小图标、按钮、背景图案等。对于这些小图片,Base64 编码可以显著减少 HTTP 请求的数量,从而提升页面加载速度。


在实际Web项目开发中,使用 Webpack Vite 将小图片自动转换为 Base64 编码是一个常见的优化方法。这种自动化的处理可以简化开发流程,并确保在构建过程中优化资源。


webpack 配置示例:

module.exports = {
  module: {
  rules: [
  {
  test: /\.(png|jpe?g|gif)$/i,
  use: [
  {
  loader: 'url-loader',
  options: {
 limit: 10240, // 10KB
 },
 },
 ],
 },
 ],
 },
};

Vite 配置示例:

import { defineConfig } from 'vite';

export default defineConfig({
 build: {
 assetsInlineLimit: 10240, // 10KB
 },
});

在以上配置中,limit assetsInlineLimit 选项指定了图片转为 Base64 编码的阈值,超过这个阈值的图片将被单独打包为文件,而小于这个阈值的图片将被转为 Base64 编码

五、结语

通过结合多种图片加载与优化技术,可以提升页面性能,提供更好的用户体验。预加载、懒加载、渐进式加载等技术在不同场景下有着不同的优势,通过合理地选择和组合这些技术,可以有效地优化图片加载过程。


在实际项目中,建议根据项目的具体需求,选择合适的技术和工具进行图片优化和加载。希望本文所介绍的技术和示例代码能够帮助您更好地实现图片批量处理与加载优化,提升网页的加载速度和用户体验。


WEB 图片优化的相关文章到此结束,希望对你有所帮助。如果有任何问题或建议,欢迎在评论区留言,谢谢!



作者:之家-梁家玮

来源-微信公众号:之家前端共享流

出处:https://mp.weixin.qq.com/s/bhxtIED32lJP7PY9g28GNA

、webpack中使用css文件:

loader是webpack中一个非常核心的概念,去转化webpack不能转化或打包的文件。

安装loader:

官网介绍:

安装: cnpm install --save-dev css-loader

loader配置:

然后再进行打包动作:npm run build

PS:css-loader只负责将css文件进行加载,所以还需要style-loader负责将样式添加到DOM中,让css文件起作用,通过cnpm install style-loader --save-dev 安装环境

// css-loader只负责将css文件进行加载

// style-loader 负责将样式添加到DOM中

// 使用多个loader时,是从右到左进行执行的

然后通过npm run build 打包,运行,测试成功:


二、webpack-less的使用

Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。Less 可以运行在 Node 或浏览器端。

安装less环境:cnpm install --save-dev less-loader less

然后在webpack.config.js配置less环境:

然后重新打包,运行,测试成功:

PS:安装过程中,高版本的在打包时会报错,建议还是与其他组件配套的版本进行安装,我这边是安装了cnpm install --save-dev less-loader@4.1.0 less


三、webpack的图片使用

图片处理,需要用到url-loader 像 file loader 一样工作,但如果文件小于限制,可以返回 data URL

安装环境:cnpm install --save-dev url-loader@4.1.0

配置环境:

PS:当加载的图片大小于limit时,会将图片编译成base64字符串形式;

如果加载的图片大于limit时,则需要file-loader的环境进行加载,否则打包时会报错,此时直接安装相关环境即可,不需要配置:cnpm install --save-dev file-loader@4.1.0 。

但是通过file-loader打包的url文件,系统会去打包文件夹dist目录下找相关文件,需要指定加载图片的位置,所以在配置文件中增加一个属性:publicPath: 'dist/' //只要打包涉及到URL的文件,则自动在路径前面增加一个dist/的路径:

重新打包,测试运行成功(已经添加背景图片):

file-loader的情况:

PS:通过file-loader打包的图片,是一个32位hash值,目的是为了防止名字重复:

为了使名字规范,可以在配置文件options进行配置,图片名字再拼接一个8位的hash值:

name: 'img/[name].[hash:8].[ext]' // 注意格式

重新打包后则生成一个原来名字拼接上一个8位hash值名字的图片:

运行后的结果: