前端进阶必备: Web 图片优化指南

未优化的图片是影响网站性能的主要因素之一,尤其会影响初次加载。取决于图像的分辨率和画质,图片可能占据整个网站流量的 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 大小的图片要花很久才能加载完毕。如果等待网站加载的用户大部分时间花在等待单张图片加载,那网站会损失不少流量。想想就可怕,是吗?

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

在线图片优化

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

image

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>

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

  • 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,可以作为命令行工具使用,也可以作为构建工具的插件使用:

图片加载优化

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

懒加载

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

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

在这里插入图片描述

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">在这里插入图片描述</figcaption>

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

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

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

渐进式图片

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

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

image

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>

类似于先加载页面的骨架,渐进式图片这一技术让用户产生图片加载变快的印象。用户不再盯着一片空白区域等待事情发生,而能看到图像变得越来越清晰。
渐进式图片有基于 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="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="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="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 加速图片(和其他静态资源)。

image

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;"></figcaption>

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容