图片优化不完全指北

3,512 阅读17分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

前言

图片是一个网站的重要组成部分,图片影响这页面的美观和品质。简单来说图片对于网站建设的作用就是吸引用户、彰显网站风格、美化网站、简化网站页面,所以图片在网站中起到的作用完全不亚于软文,有的甚至效果比软文还要好。但是图片的不合理使用可能会影响页面的打开速度和用户的正常浏览,在对网站进行优化的时候,可以从图片这一方面入手。

如何为不同场景选择不同的图片格式?

JPEG(Joint Photographic Experts Group)

JPEG(Joint Photographic Experts Group)是 JPEG 标准的产物,该标准由国际标准化组织(ISO)制订,是面向连续色调静止图像的一种压缩标准。 JPEG 格式是最常用的图像文件格式,后缀名为 .jpg 或 .jpeg 。

优势

  • 它支持极高的压缩率,因此JPEG图像的下载速度大大加快。
  • 它能够轻松地处理16.8M颜色,可以很好地再现全彩色的图像。
  • 在对图像的压缩处理过程中,该图像格式可以允许自由地在最小文件尺寸(最低图像质量)和最大文件尺寸(最高图像质量)之间选择。
  • 该格式的文件尺寸相对较小,下载速度快,有利于在带宽并不“富裕”的情况下传输。

劣势

  • 并非所有的浏览器都支持将各种JPEG图像插入网页。
  • 压缩时,可能使图像的质量受到损失,因此不适宜用该格式来显示高清晰度的图像。

适合

颜色丰富的图片、彩色图、大焦点图、通栏 banner 图、不规则的图片等...

不适合

线条图形、文字/图片图形等...

PNG(Portable Network Graphics)

png 是一种采用无损压缩算法的位图格式,其设计目的是试图替代GIFTIFF文件格式,同时增加一些GIF文件格式所不具备的特性。PNG使用从LZ77派生的无损数据压缩算法,一般应用于JAVA程序、网页或S60程序中,原因是它压缩比高,生成文件体积小。

PNG格式有8位、24位、32位三种形式,其中8位PNG支持两种不同的透明形式(索引透明和alpha透明),24位PNG不支持透明,32位PNG在24位基础上增加了8位透明通道,因此可展现256级透明程度。

PNG8和PNG24后面的数字则是代表这种PNG格式最多可以索引和存储的颜色值。8代表2的8次方也就是256色,而24则代表2的24次方大概有1600多万色。

优势

  • 无损压缩
  • 完全支持 alpha 透明度。
  • 可以重复保存且不降低图像质量

劣势

  • 体积偏大

适合

纯色、透明、线条绘图、图标、边缘清晰,有大块相同颜色区域。颜色数较少,但是需要半透明。

不适合

由于无损存储,图片体积较大,不适合需要图片特别大的场景。

SVG(Scalable Vector Graphics)

SVG是一种图形文件格式,它的英文全称为Scalable Vector Graphics,意思为可缩放的矢量图形。严格来说应该是一种开放标准的矢量图形语言,可让你设计激动人心的、高分辨率的Web图形页面。用户可以直接用代码来描绘图像,可以用任何文字处理工具打开SVG图像,通过改变部分代码来使图像具有交互功能,并可以随时插入到HTML中通过浏览器来观看。

优势

  • SVG 可被非常多的工具读取和修改
  • SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强
  • SVG 可在图像质量不下降的情况下被放大

劣势

  • 不是所有的浏览器都支持SVG,IE8和早期版本都需要一个插件
  • 复杂的图片会降低渲染速度(只支持小图)

IE8和早期版本的 ie 浏览器,如果想在页面中展现 svg 图片,需要安装 adobe 的 SVGView 插件。

适合

高分辨率打印图片程序、设计动画、演示等...

不适合

对渲染速度要求比较大的网站,不适合需要图片特别大的场景。

GIF(Graphics Interchange Format)

GIF是一种位图。位图的大致原理是:图片由许多的像素组成,每一个像素都被指定了一种颜色,这些像素综合起来就构成了图片。GIF采用的是Lempel-Zev-Welch(LZW)压缩算法,最高支持256种颜色。由于这种特性,GIF比较适用于色彩较少的图片,比如卡通造型、公司标志等等。如果碰到需要用真彩色的场合,那么GIF的表现力就有限了。GIF通常会自带一个调色板,里面存放需要用到的各种颜色。在Web运用中,图像的文件量的大小将会明显地影响到下载的速度,因此我们可以根据GIF带调色板的特性来优化调色板,减少图像使用的颜色数(有些图像用不到的颜色可以舍去),而不影响到图片的质量。

优势

  • GIF是压缩格式的文件,用于减少文件在网络上传递的时间
  • 支持无损耗压缩和透明度。动画 GIF 很流行,易于使用许多 GIF 动画程序创建

劣势

  • GIF 只支持 256 色调色板,因此,详细的图片和写实摄影图像会丢失颜色信息,而看起来却是经过调色的

适合

动画、图标。

不适合

不适合存储色彩图片。

WEBP

WebP 是一种同时提供了有损压缩无损压缩(可逆压缩)的图片文件格式。WebP支持的像素最大数量是16383x16383。有损压缩的WebP仅支持8-bit的YUV 4:2:0格式。而无损压缩(可逆压缩)的WebP支持VP8L编码与8-bit之ARGB色彩空间。又无论是有损或无损压缩皆支持Alpha透明通道、ICC色彩配置、XMP诠释数据。

WebP 有静态与动态两种模式。动态 WebP(Animated WebP)支持有损与无损压缩、ICC色彩配置、XMP诠释数据、Alpha 透明通道。

优势

  • 支持无损压缩和有损无损
  • 占用体积小
  • 可支持透明

劣势

  • 兼容性不好

适合

适合图形和半透明图像。

不适合

只有 256 色,不适合彩色图片,不适合色彩丰富的图片。

怎么让图片加载得更快

用工具压缩图片

压缩 png:node-pngquant-native

这个工具,跨平台,压缩比高,压缩 png24 非常好。

node-pngquant-native

测试源码

var pngquant = require('node-pngquant-native');
var fs = require('fs');
var path = require('path')

fs.readFile(path.resolve(__dirname, './image/product.png'), function (err, buffer) {
  if (err) throw err;
  var resBuffer = pngquant.compress(buffer, {
    "speed": 1
  });

  fs.writeFile(path.resolve(__dirname, './image/produc_out.png'), resBuffer, {
      flags: 'wb'
  }, function(err){
    console.log(err);
  });
});

压缩值 50 % 左右。

压缩 jpg:jpegtran

跨平台,有 Linux、Mac、Windows 的解决方案。

jpegtran

// 全局安装
$ npm install --save jpegtran
// 命令行执行
$ jpegtran -copy none -optimize -outfile [输出文件路径] [输入文件路径]

压缩值 15 % 左右。

压缩 gif:gif:Gifsicle

通过改变每一帧的比例,减少 gif 的大小。它可以将多个 GIF 合并为一个 GIF 动画;将动画分解为其组件帧;更改动画中的单个帧;打开和关闭隔行扫描;增加透明度;为动画添加延迟、处理和循环;添加和删除评论;翻转和旋转;优化空间动画;更改图像的颜色图;和其他东西。

Gifsicle 主页

Gifsicle GitHub

// 全局安装
$ npm install --global gifsicle
// 命令行执行
$ gifsicle --optimize=3 -o [输出文件路径] [输入文件路径]

压缩值 30 % 左右。

图片尺寸随网络环境变化

在不同的网络环境下,加载不同尺寸和像素的图片。一般都是通过图片 URL 的参数来改变图片的尺寸。

响应式图片

根据用户的设备和使用场景提供合适的图片。对于开发者来说不可能预见用户使用的浏览器的所有设置,只有浏览器在打开和渲染的时候才会知道它设备的具体情况(屏幕大小、能力、尺寸等)。针对这些请求,开发者一般会准备不同版本的图片,例如:大、中、小,不同版本的图片对于不同屏幕大小和分辨率。选择最适合的视图尺寸往往能减少图片的大小,让图片加载的更快。

srcset 切换分辨率

<img 
  src="纸箱回收.png" 
  srcset="金属类.png 1.1x, 布料类.png 1.2x"
/>

测试源码

注意: 在 Chrome 中测试时,通过如下方式禁用缓存:打开 DevTools ,并选中 Settings > Preferences > Network下Disable cache的选择框。否则,Chrome 会优先选择缓存图片而不是恰好适配的那个。

src 属性是我们非常熟悉的一个属性,在这里有两个作用:

  • 指定 1x 大小的图片
  • 在浏览器不支持 srcset 属性时的后备方案

srcset 属性(浏览器支持的情况下),通过逗号分割图片的描述,让浏览器自己决定使用哪一个图片。

但是不幸的是,这种写法会带来一些问题,例如 375像素 1x 、900像素 1.25x 都是使用的相同的图片,这其实并不是我们想要的结果。

srcset & sizes 联合切换

<img 
  srcset="uswnt-480.png 480w, 
    uswnt-640.png 640w, 
    uswnt-960.png 960w,
    uswnt-1280.png 1280w" 
  sizes="(max-width: 480px) 50vw, 
  (max-width: 640px) 25vw, 
    (max-width: 960px) 50vw, 
    (max-width: 1280px) 50vw, 
    640px" 
  src="uswnt-640.png" alt="" />

测试源码

利用srcset和sizes信息来选择最符合规定条件的图像。

我测试电脑的 dpr = 2;

  • 如果浏览器的 viewport 为小于等于 480 像素,图片宽高为 50%(宽高 = 480 * 0.5),浏览器视图加载一张 480 * 0.5 * dpr(2) = 480像素的图片,uswnt-480.png。

  • 如果浏览器的 viewport 为小于等于 640 像素,图片宽高为 25%(宽高 = 640 * 0.25),浏览器视图加载一张 640 * 0.25* dpr(2) = 320 像素的图片,浏览器会尝试加载一张靠近尺寸的图片 uswnt-480.png(如图一所示)。
    • 如果我这里将 25 vw 修改为 40 vw,640 * 0.4* dpr(2) = 512,相对 640 和 480 更加接近 480 所以会显示 uswnt-480.png(如图二所示)。
    • 如果我这里将 25 vw 修改为 45 vw,640 * 0.45* dpr(2) = 576,相对 640 和 480 更加接近 640 所以会显示 uswnt-640.png(如图三所示)。

图一

图二

图三

注意:sizes 属性仅仅是对浏览器给出提示,并不能保证浏览器就会言听计从。所以我们无法确定究竟显示哪张图像,因为每个浏览器根据我们提供的信息挑选适当图像的算法是有差异的。srcset 和 size 列表是对浏览器的一个建 议(hint),而非指令。例如,设备像素比(dpr)为1.5的设备,亦可用1x也可用2x的图像,由浏览器根据其能力、网络等因素来决定

picture 元素

HTML 元素通过包含零或多个 元素和一个 元素来为不同的显示/设备场景提供图像版本。浏览器会选择最匹配的子 元素,如果没有匹配的,就选择 元素的 src 属性中的 URL。然后,所选图像呈现在元素占据的空间中。

<picture>
    <source srcset="/media/cc0-images/surfer-240-200.jpg"
            media="(min-width: 800px)">
    <img src="/media/cc0-images/painted-hand-298-332.jpg" alt="" />
</picture>

要决定加载哪个 URL,user agent 检查每个 的 srcsetmediatype 属性,来选择最匹配页面当前布局、显示设备特征等的兼容图像。

media 属性

media 属性允许你提供一个用于给用户代理作为选择 元素的依据的媒体条件 (media condition)(类似于媒体查询)。如果这个媒体条件匹配结果为 false,那么这个 元素会被跳过。

<picture>
  <source srcset="1.png" media="(min-width: 600px)">
  <img src="2.png" alt="MDN">
</picture>

type 属性

type 属性允许你为 元素的 srcset 属性指向的资源指定一个 MIME 类型。如果用户代理不支持指定的类型,那么这个 元素会被跳过。

<picture>
   <source srcset="1.svg" type="image/svg+xml">
   <img src="1.png" alt="MDN">
 </picture>

srcset 属性

和前面的作用是一样的这里就不多赘述了。


如果要为高 DPI (Retina) 显示提供更高像素密度的图像版本,请在 元素上使用 srcset 。这使得浏览器可以在节约流量模式下选择低像素密度版本,且不需要您编写明确的 media 条件。

在任何情况下,你都必须在 之前正确提供一个元素以及它的src和alt属性,否则不会有图片显示。当媒体条件都不返回真的时候,它会提供图片;如果浏览器不支持 元素时,它可以作为后备方案。

不建议使用 CSS 或 JavaScript 来做响应式图片的效果?

当浏览器开始加载一个页面, 它会在主解析器开始加载和解析页面的 CSS 和 JavaScript 之前先下载 (预加载) 任意的图片。这是一个非常有用的技巧,平均下来减少了页面加载时间的20%。但是, 这对响应式图片一点帮助都没有, 所以需要类似 srcset的实现方法。因为你不能先加载好 元素后, 再用 JavaScript 检测可视窗口的宽度,如果觉得大小不合适,再动态地加载小的图片替换已经加载好的图片,这样的话, 原始的图像已经被加载了, 然后你又加载了小的图像, 这样的做法对于响应式图像的理念来说,是很糟糕的。

图片逐渐加载

统一占位符

在图片还处于加载中时,通常需要填充页面预览效果,这时往往会用到图片占位符,例如:天猫、京东使用一个 div 来充当图片加载中的占位。

我们也可以使用 js 的手段,动态的修改 img 的 src 达到占位的效果。

 <style>
   div {
     height: 1024px;
     width: 1024px;
   }
   img {
     position: relative;
     height: 100%;
     width: 100%;
   }
    
   img::after {
     content: "";
      height: 100%;
      width: 100%;
      position: absolute;
      background: url(1.png) no-repeat center;
    }
</style>
<body>
    <div>
        <img src="">
    </div>
</body>

<script>
    setTimeout(function() {
        document.querySelectorAll("img")[0].src = '2.png';
    }, 3000);
</script>

LQIP: Low Quality Image Placeholders

根据原始图片自动生成超小尺寸的缩略图。

const lqip = require('lqip');

const file = `./dest/to/file/zouhir-riding-a-bike.jpg`;

lqip.base64(file).then(res => {
  console.log(res); // "data:image/jpeg;base64,/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhY.....
});

注意:lqip 只支持 'jpeg', 'jpg', 'png'

利用生成的 base64 来填充 src,但是我们在实际的项目中肯定不能手动的为每一张图片都用 lqip 生成一个 base64 填充到 img 中,这样效率也太慢了。所以工程化的角度有一个 lqip-loader 为JS 包中导入的 jpeg 图像生成 Base64。

lqip-loader

并且针对 Base64,在 Chrome 为了节省内存和提高 GPU 性能,浏览器(包括从 61.0.3163.38 开始的 Chrome)现在将呈现稍微更清晰或像素化的 Base64 编码图像。

左侧是旧版 Chrome,右侧是 Chrome v61

SQIP:SVG-based LQIP technique

SQIP 将生成基于 SVG 的图像预览。它们可以用作延迟加载图像预览、视频缩略图或项目的艺术元素。

SQIP

图片可以被替代?

我们前面提到为了让「图片加载的更快」,我们常常使用:

  • 工具压缩图片,减少图片的大小,来提升加载速度
  • 图片尺寸随网络变化,选择不同尺寸不同格式的图片,来降低显示图片的大小,从而提升加载速度
  • 图片逐渐加载,利用占位符来降低图片加载慢的用户体验

但是我们真的一定需要图片吗?或许在一些场景下(注意:并不是所有场景),我们可以替换图片。

webfonts

HTML5 为我们提供了一种选择:webfonts。 字体集可以包含图形图标和字符集。Webfonts可以替代图形:

Icon Font Demonstration

Webfont 图标的优点:

  • 字体可以缩放到任意大小,使用任何颜色并应用CSS效果
  • webfonts 提供了良好的跨浏览器兼容性,甚至可以在IE6中使用
  • 单个字体文件可能比多个图像更有效

Webfont图标的缺点:

  • 字体字符是单色的(尽管CSS3效果可以帮助)
  • 生成字体不像 PNG 或 SVG 那样容易
  • 如果只需要几个图标,则图像文件的大小会较小。

Data URI

Data URI其实就是将图片数据转成base64字符串格式,再引入,相比普通的引入方式它不再需要发起网络请求,从而达到优化网页快速加载的目的(减少http请求)。

Data URI适用的场景

  • 图片体积较小,没必要浪费一次http请求
  • 访问外部资源受限或者很麻烦的情况
  • 外部图片为动态的

Data URI引入方式的一些缺点

  • Base64编码的数据体积是原始二进制图片的4/3,也就是大1/3
  • 虽然相比普通引入加载更快,但是渲染更加耗时。实验结果显示 Data URI 的渲染比普通图片多消耗 53% 左右的CPU资源,内存多出4倍左右,耗时平均高出24.6倍,所以要在可接受的范围内适量使用
  • 不会被浏览器缓存(可以通过css引入的方式来缓存)

服务器端优化图片

图片服务器自动优化是可以在图片 URL 链接上增加不同参数,服务器自动生成不同格式、大小、质量的一种技术。例如在前面提到的「图片尺寸随网络环境变化」通过修改 URL 参数来达到目的也就是这样一个例子。

常见的服务端处理功能

  • 图片裁剪:按照长度、宽度、固定大小、长边、短边、填充、拉伸等缩放
  • 图片格式装换:支持不同图片格式 jpg、gif、png、webp,支持不同的图片压缩率
  • 图片处理:添加图片水印、模糊等
  • AI 处理:图片鉴别、抠图、排版、配色、合成等

服务端优化实现技术

  • 将图片压缩、裁剪、格式转换等本地攻击部署到线上图片服务器上
  • 内部运营或外网用户上传本地图片到图片服务知乎,服务器默认处理转换为多种格式,并推送到图片 CDN 服务器上
  • 图片服务器对外开放多个域名,同事对各个业务线开发不同的业务路径
  • 外网永华请求带特殊参数的图片 URL 时,图片服务器根据 URL 种不同的参数类型,从本地缓存中存取,或者实现对图片进行即时处理,返回给客服端

总结

本文从总结了图片优化的四个大的方面:

  • 不同场景选择不同的图片格式
  • 如何让图片更快的加载
  • 图片的替代方案
  • 服务器端对图片的优化

在之前我们在做网站优化的时候总是把重点放在了站点的内容、结构、外链等诸多方面,往往会忽略及其重要的一方面,那就是图片的优化。可能有小伙伴讲了,图片不就是添加上去,能有什么需要优化的。其实不然近几年搜索引擎对于图片识别功能不断完善,加上人工智能的进步,因此小伙伴们对于图片的优化必须重视起来。

参考