未优化的图片是影响网站性能的主要因素之一,尤其会影响初次加载。取决于图像的分辨率和画质,图片可能占据整个网站流量的 70%.

生产环境出现未优化的图片并显著影响初次加载速度的现象还是挺常见的。缺乏经验的开发者通常没有意识到这一潜在问题,也不了解各种优化图片的工具和方法。

本文的目标是介绍优化 web 图片的主要工具和方法。

计算 JPG 文件尺寸

未压缩图片的尺寸很容易计算,只需将图片的长宽相乘(px 值),再乘以 3 字节(因为 RGB 色彩系统使用 24 个位元)。所得结果除以 1,048,576(1024 * 1024)即得到兆字节。

image_size = (image_width * image_height * 3) / 1048576

比如,计算分辨率为 1366px x 768px 的未压缩图片的大小:

1366 * 768 * 3 / 1048576 = 3Mb

现在网站的尺寸平均在 2Mb 和 3Mb 之间,想象一下,一张未压缩的图片就占掉了 80% 的流量。在网速较慢的移动网络上,3Mb 大小的图片要花很久才能加载完毕。如果等待网站加载的用户大部分时间花在等待单张图片加载,那网站会损失不少流量。想想就可怕,是吗?

所以,在保证图片分辨率和画质可接受的前提下,我们可以做什么来优化下图片呢?

在线图片优化

如果你的项目是一个简单的静态网站,只有少量不经常变动(甚至从来不会变动)的图片,那么你可以直接使用在线工具。这些工具使用各种算法压缩图像,效果很不错,对简单项目而言完全够用。

就我个人所知,比较著名的在线工具有:

  • Compressor.io,支持 JPG、PNG、SVG、GIF,每次上传 1 个文件
  • Squoosh,支持 JPG、PNG、SVG、GIF,每次上传 1 个文件
  • Optimizilla,支持 JPG、PNG,最多每次上传 20 个文件
  • TinyPNG,支持 JPG、PNG,最多每次上传 20 个文件
  • SVGMinify,支持 SVG,每次上传 1 个文件
  • svgomg,支持 SVG,每次上传 1 个文件

自动化解决方案

然而,如果你做的是多人协作的复杂项目,使用大量图片,在加入每张图片时都手动操作一下很乏味。同时,还存在由于人为错误或其他因素导致一些图片没有优化的风险。

复杂项目常常使用同样复杂的构建系统,比如 GulpWebpackParcel。配置一下这类构建系统,加入图片优化插件很方便。这样就可以完全自动化图片优化过程,在项目中加入图片后就可以优化它们。

就我所知,最有名的插件是 imagemin,可以作为命令行工具使用,也可以作为构建工具的插件使用:

  • imagemin-cli
  • gulp-imagemin
  • imagemin-webpack
  • parcel-plugin-imagemin

图片加载优化

我们前面介绍了如何通过压缩图片降低文件尺寸,但不过多改变图片分辨率和影响画质。尽管优化图片后文件尺寸能降低不少,但一次性加载大量优化过的图片(比如电商网站的商品列表页面)还是会影响性能。

懒加载

懒加载也叫按需加载,意思是仅加载当前视图(用户屏幕显示范围)内的图片,不加载其他图片(直到它们出现在当前视图内时才加载)。

只有较新版本的浏览器才支持原生的懒加载特性,不过有许多基于 JavaScript 的方案。

  • 原生懒加载
<img src="data:image.jpg" loading="lazy" alt="Sample image" />
  • 基于 JavaScript 的方案

就我所知,最知名的方案有:

verlok/lazyload
yall.js
Blazy (现在没有维护)

渐进式图片

尽管懒加载在性能方面表现出色,但是用户滚动屏幕后需要盯着空白区域等待图片加载,这样的用户体验不太好。网速慢的情况下,下载图片会非常慢。所以我们还需要渐进式图片。

渐进式图片的意思是在高画质图像加载完之前会先显示低画质版本。低画质版本由于画质低、压缩率高,尺寸很小,加载很快。在两者之间我们也可以根据需要显示不同画质的版本。

类似于先加载页面的骨架,渐进式图片这一技术让用户产生图片加载变快的印象。用户不再盯着一片空白区域等待事情发生,而能看到图像变得越来越清晰。
渐进式图片有基于 JavaScript 实现的方案:
progressive-image。

响应式图片

我们还需要留意使用尺寸合适的图片。

例如,假设图片在桌面浏览器上显示的最大宽度为 1920px,平板上的最大宽度为 1024px,手机上的最大宽度为 568px,那么最简单的方案是使用 1920px 的图片,这样可以满足所有场景。不过,这种情况下,网速慢、网络不稳定的智能手机用户需要等很久图片才能加载完毕,这就又碰到了我们文章开头提到的问题。

好在我们可以通过 picture 元素告诉浏览器基于媒体查询下载相应的图片。尽管现在 93% 的用户使用的浏览器都支持这一特性,但是这个元素内部还是包含了一个 img 元素,以兼容不支持这一特性的浏览器。

<picture>  <source media="(min-width: 1025px)" srcset="image_desktop.jpg">  <source media="(min-width: 769px)" srcset="image_tablet.jpg">  <img src="data:image_mobile.jpg" alt="Sample image"></picture>

使用 CDN

Cloudinary、Cloudflare 之类的 CDN 服务可以在服务器上优化图片,将优化后的图片传送给用户。如果你的站点使用 CDN,可以看下静态资源优化选项。这样我们就不用操心图片优化,由 CDN 在服务端完成优化。我们只需要操心懒加载、渐进式图片等前端的加载方案。

WebP 图像格式

WebP 是由 Google 开发的专为 web 优化的图像格式。根据 canIUse 的数据,大部分用户使用的浏览器支持 WebP 格式。另外使用 picture 元素也可以很方便地兼容不支持 WebP 的浏览器。

<picture>  <source type="image/webp" srcset="image.webp" />  <source srcset="image.jpg" />  <img src="data:image.jpg" alt="Sample image" /></picture>

有很多在线文件格式转换工具可以把图片转为 WebP 格式,不过 CDN 服务可以在服务端完成这一格式转化。

为高分屏优化

考虑高分屏很有必要,不过这个更多的是用户体验优化。

例如,假定我们在 768px 的屏幕上显示一张 768px x 320px 的图片。但是屏幕有 2x 的密度,也就是说屏幕宽度实际是 2 x 768 = 1536 px。这就意味着我们将 768 px 的图片拉升到 1536 px,这就导致高分屏上的图片看起来很模糊。

为了解决这一问题,我们需要提供为高分屏优化的图片。我们需要单独创建相当于普通屏幕 2 倍或 3 倍分辨率的图片,然后在 srcset 属性上使用 2x 标签表明这是为高分屏准备的图片。

<img src="data:image-1x.jpg" srcset="image-2x.jpg 2x" alt="Sample image" />

例子

支持高分屏的响应式 WebP/PNG 图片:

<picture>    <source srcset="./images/webp/hero-image-420-min.webp 1x, ./images/webp/hero-image-760-min.webp 2x" type="image/webp" media="(max-width: 440px)">    <source srcset="./images/minified/hero-image-420-min.png 1x, ./images/minified/hero-image-760-min.png 2x" media="(max-width: 440px)">    <source srcset="./images/webp/hero-image-550-min.webp 1x, ./images/webp/hero-image-960-min.webp 2x" type="image/webp" media="(max-width: 767px)">    <source srcset="./images/minified/hero-image-550-min.png 1x, ./images/minified/hero-image-960-min.png 2x" media="(max-width: 767px)">    <source srcset="./images/webp/hero-image-420-min.webp 1x, ./images/webp/hero-image-760-min.webp 2x" type="image/webp" media="(max-width: 1023px)">    <source srcset="./images/minified/hero-image-420-min.png 1x, ./images/minified/hero-image-760-min.png 2x" media="(max-width: 1023px)">    <source srcset="./images/webp/hero-image-760-min.webp 1x, ./images/webp/hero-image-960-min.webp 2x" type="image/webp" media="(max-width: 1919px)">    <source srcset="./images/minified/hero-image-760-min.png 1x, ./images/minified/hero-image-960-min.png 2x" media="(max-width: 1919px)">    <source srcset="./images/webp/hero-image-960-min.webp" type="image/webp">    <source srcset="./images/minified/hero-image-960-min.png">    <img  src="./images/minified/hero-image-960-min.png" alt="Example"></picture>

结语 —— 优化优先级

  1. 使用优化后的图片(使用自动构建工具、在线服务、CDN 优化)
  2. 使用懒加载(在浏览器有更好的原生支持前考虑使用 JS 方案)
  3. 为高分屏优化图片
  4. 使用 WebP 格式
  5. 使用渐进式图片

可选: 如果条件允许,记得使用 CDN 加速图片(和其他静态资源)。

内容经授权转载自 New Frontend 网站。

如何处理 Web 图片优化?的更多相关文章

  1. Web性能优化:图片优化

    程序员都是懒孩子,想直接看自动优化的点:传送门 我自己的Blog:http://cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到 ...

  2. Web前端性能优化之图片优化

    我自己的Blog:http://blog.cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到了互联网内容总量的62%,也就是说超过 ...

  3. [转] Web前端优化之 图片篇

    原文链接: http://lunax.info/archives/3101.html Web 前端优化最佳实践第六部分面向 图片(Image),这部分目前有 4 条规则.在最近的 Velocity 2 ...

  4. Web 性能优化: 图片优化让网站大小减少 62%

    摘要: 压缩各种格式的图片. 原文:Web 性能优化: 图片优化让网站大小减少 62% 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是 Web 性能优化的第二篇,上一篇在下面看点 ...

  5. Web 性能优化:Preload与Prefetch的使用及在 Chrome 中的优先级

    摘要: 理解Preload与Prefetch. 原文:Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级 作者:前端小智 Fundebug经授权转载,版权归原作者所 ...

  6. 常见 Web 性能优化方式

    这篇文章是我阅读 Web Performance 101 之后的进行的粗糙的翻译作为笔记,英语还行的童鞋可以直接看原文. 这篇文章主要介绍了现代 web 加载性能(注意不涉及代码算法等),学习为什么加 ...

  7. 关于大型网站技术演进的思考(二十一)--网站静态化处理—web前端优化—下【终篇】(13)

    本篇继续web前端优化的讨论,开始我先讲个我所知道的一个故事,有家大型的企业顺应时代发展的潮流开始投身于互联网行业了,它们为此专门设立了一个事业部,不过该企业把这个事业部里的人事成本,系统运维成本特别 ...

  8. 关于大型网站技术演进的思考(二十)--网站静态化处理—web前端优化—中(12)

    Web前端很多优化原则都是从如何提升网络通讯效率的角度提出的,但是这些原则使用的时候还是有很多陷阱在里面,如果我们不能深入理解这些优化原则背后所隐藏的技术原理,很有可能掉进这些陷阱里,最终没有达到最佳 ...

  9. 关于大型网站技术演进的思考(十九)--网站静态化处理—web前端优化—上(11)

    网站静态化处理这个系列马上就要结束了,今天我要讲讲本系列最后一个重要的主题web前端优化.在开始谈论本主题之前,我想问大家一个问题,网站静态化处理技术到底是应该归属于web服务端的技术范畴还是应该归属 ...

随机推荐

  1. 2.restEasy中@PathParam和@QueryParam的区别

    例如代码: @GET @Path("/{id}") @Produces(MediaType.APPLICATION_JSON) public T query(@PathParam( ...

  2. 洛谷P1086 花生采摘

    https://www.luogu.org/problem/P1086 #include <bits/stdc++.h> using namespace std; typedef long ...

  3. decimal与float和double的区别

    一直很奇怪C#的预定义数据类型中为什么加了一个decimal,有float和double不就够了吗?今天来挖一挖. 浮点型 Name CTS Type De script ion Significan ...

  4. 题解【Codeforces859C】Pie Rules

    题面 一道需要一定思考的 \(\text{DP}\) . 设 \(dp_i\) 表示第 \(i\) 步走的人能得到的最大分数, \(sum_i\) 表示 \(\sum_{j=i}^n a_j\) ,即 ...

  5. 剑指offer 面试题. 数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值.我们 ...

  6. HBase 中读 HDFS 调优

    HDFS Read调优 在基于 HDFS 存储的 HBase 中,主要有两种调优方式: 绕过RPC的选项,称为short circuit reads 开启让HDFS推测性地从多个datanode读数据 ...

  7. 4.用springboot写的第一个程序--helloworld

    这是我自己在controller层建的hello类 运行,选画方框的那个.我查了一晚上,可算知道为啥运行不了了. 然后再浏览器输入网址就ok了 为了大力!好好学习!

  8. 题解【Codeforces438D】The Child and Sequence

    题目描述 At the children's day, the child came to Picks's house, and messed his house up. Picks was angr ...

  9. Day4 注解 泛型

    注解是什么 注释是绑定到程序源代码元素的元数据,对它们运行的​​代码的操作没有影响. https://blog.csdn.net/SDDDLLL/article/details/93509699 他们 ...

  10. winform学习(11)Timer控件

    利用Timer控件制作简单的跑马灯: 拉一个Lable控件至窗体中心,Text内容为★▶◀★▶◀★▶◀★▶◀ 再拉一个Timer控件,属性Enabled设置为True(即开启控件),Interval设 ...