优化实战 第 20 期 - 图片的优化策略,推荐 AVIF

5,076 阅读4分钟

图片是页面上重要的组成部分,在页面加载的过程中,应当优先让图片和文字最快的展示,从而提高页面的加载速度。

图片JPG格式

  • 图片特点

    JPG 格式以 24 位存储单个图,可以呈现多达 1600 万种颜色,足以应对大多数场景下对色彩的要求,这一点决定了它压缩前后的质量损耗并不容易被我们人类的肉眼所察觉。

  • 图片特性

    有损压缩 体积小 加载快 不支持透明

  • 使用场景

    适用于呈现色彩丰富的图片,经常作为 大的背景图、轮播图或 Banner 图

图片PNG-8与PNG-24格式

  • 图片特点

    PNG-8 最多支持 256 种颜色,而 PNG-24 可以呈现约 1600 万种颜色。PNG 图片比 JPG 图片具有更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。

  • 图片特性

    无损压缩 质量高 体积大 支持透明

  • 使用场景

    适用于呈现 小的 Logo、颜色简单且对比强烈的图片或背景等

图片SVG格式

  • 文件概览

    SVG 是一种矢量图格式,可以 无限放大而且不会失真

  • 对比JPG和PNG的优势

    文本文件 文件体积更小 可压缩性更强

  • 使用方式

    可以直接写在 HTML 里成为 DOM 的一部分,也可以作为 .svg 后缀的独立文件,在使用上和普通图片一样。

  • 使用场景

    适合响应式设计和不同分辨率的设备 | 在线矢量图库

图片Base64编码

  • 编码概览

    Base64 是一种索引编码,每个字符都对应一个索引,具体的关系图,如下:

    base64.webp

    Base64 是基于 64 个可打印字符来表示二进制数据的编解码方式

    可打印字符包括大写字母 A-Z 、小写字母 a-z、数字 0-962 个字符,再加上 2+/

  • 使用方式

    在使用上和普通图片一样,将编码后的字符串作为图片 src 或背景的 url 内容

  • 使用场景

    作为小图标解决方案而存在,目的为了 减少加载网页图片时对服务器的请求次数,从而提升网页性能

  • 工具推荐

    推荐使用 webpackurl-loader 来进行 Base64 编码。它可以根据文件的大小,判断图片是否有必要进行编码。

图片WebP格式

  • 图片特点

    WebP 是一种同时提供了 有损压缩无损压缩 的图片文件格式

    在动画图像文件的情况下,将 GIF 图像转换为 WebP 图像会将 文件大小减少一半,同时保持图像质量

  • 图片特性

    支持透明度 支持动图,且文件体积更小

  • 注意事项

    浏览器兼容性较差,特别是在某些旧版浏览器上。

  • 兼容性检测

    const isSupportWebp = (nature = 'lossy') => {
      const strategies = Object.assign(Object.create(null), {
        'lossy': 'UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA',  //有损
        'lossless': 'UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==',  // 无损
        'alpha': 'UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==',  // 透明
        'animation': 'UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA',  // 动图
      })
      return new Promise((resolve, reject) => {
        const img = new Image()
        img.onload = () => (img.width > 0 && img.height > 0) && resolve(true)
        img.onerror = () => resolve(false)
        img.src = `data:image/webp;base64,${strategies[nature]}`
      })
    }
    
    isSupportWebp().then(bool => {
      // true 表示支持,false 表示不支持
    })
    

    通过将不同类型的 WebP 图片的 Base64 编码字符串赋给 img.src,根据图片加载是否成功来判断浏览器的支持情况。

图片AVIF格式

  • 图片特点

    AVIF 是一种同时提供了有损压缩与无损压缩的图片文件格式。比 WebP 更高效,比 JPEG/PNG 体积减少 50%+

  • 图片特性

    支持透明度 支持动画 支持HDR 最小体积 最佳画质

  • 注意事项

    浏览器兼容性较差,特别是在某些旧版浏览器上。

  • 兼容性回退策略

    <picture>
      <source srcset="image.avif" type="image/avif">
      <source srcset="image.webp" type="image/webp">
      <img src="image.jpg" alt="示例图片">
    </picture>
    
  • 适用场景

    网页优化(减少流量,提高加载速度)、移动端应用、电商 & 摄影(高质量 HDR 图片)、动画图片(替代 WebP / GIF)

图片压缩

  • 无损压缩

    使用工具如 TinypngImageOptim 等,对图片进行无损压缩,减少文件大小而不影响图片质量。

  • 有损压缩

    使用工具如 JPEG-OptimizerKraken.io 等,对图片进行有损压缩,通过降低图片质量来减少文件大小。

  • 其它工具

    使用 Squoosh 工具可以压缩超过 5M 的图片,支持 webpjpegpng 格式的图片。

    使用 Picdiet 工具可以压缩任意大小的图片,仅支持 jpg 格式的图片压缩。

响应式图片

  • 使用 srcset 和 sizes 属性

    img 标签中使用 srcsetsizes 属性,提供不同分辨率的图片,让浏览器根据设备分辨率选择合适的图片。

  • 代码实现

    <picture>
        <source srcset="image.webp" type="image/webp">
        <source srcset="image.jpg" type="image/jpeg">
        <img src="image.jpg" alt="Product Image" srcset="image-small.jpg 300w, image-medium.jpg 600w, image-large.jpg 1200w" sizes="(max-width: 600px) 300px, (max-width: 1200px) 600px, 1200px">
    </picture>
    

    通过 type 属性指定文件 MIME 类型

使用CDN服务

  • 服务概览

    专门为图片做优化的,通常包含缩放、格式转换等

    可以把它看成是一个 API,通过传入尺寸、质量、格式等参数,获取对应的图片内容

  • 使用场景

    将更新频率较低的图片可以直接放在服务器上,既能降低访问延时,又可以适用于多种不同的场景

  • 优化效果

    提高加载速度:CDN在全球多个节点缓存资源,用户可以从最近的节点获取资源,减少延迟。

    减轻服务器负担:通过分发网络请求,CDN减轻了源服务器的负载,提高了网站的稳定性。

    降低带宽成本:通过缓存内容,CDN可以减少源服务器的带宽使用量,从而降低成本。

浏览器缓存

  • 缓存策略

    通过设置 HTTP 头中的 Cache-ControlExpires,让浏览器缓存图片,减少重复加载。

  • 服务器配置

    location ~* \.(jpg|jpeg|png|gif|ico|webp|avif)$ {
      expires 30d;
      add_header Cache-Control "public, max-age=2592000, immutable"; 
    }
    

图片懒加载

  • 原生Lazy Load

    现代浏览器已经支持通过 loading 属性在 img 标签中实现原生的图片延迟加载。

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

    这样,图片会在即将进入视口时才加载,从而提高页面加载性能和用户体验。

  • 插件Lazy Load

    import 'lazysizes'
    
    window.lazySizes.init()
    
    <img class="lazyload" data-src="image.jpg" alt="描述">
    
  • 结合使用

    可以结合插件,来解决旧版浏览器的兼容性问题

图片预加载

  • 使用场景

    在页面加载过程中,优先加载用户视觉上重要或者必需的图片,以提升用户体验和网页加载速度。

  • 实现方式

    <link rel="preload" href="critical-image.jpg" as="image">
    

    使用 as="image" 告知浏览器预加载的资源是图片,这样可以使浏览器更准确地优先加载资源,并且将资源存储在缓存中在适当的情况下可以对资源进行复用。

雪碧图(CSS Sprites)

  • 核心思路

    将多个小图标和背景图片合并到一张图片上的图像拼合技术,然后利用 CSS 的背景定位 backrground-position 来控制需要显示的图片部分 | 在线生成雪碧图工具

  • 设计背景

    当应用系统中的小图标和小图片过多时,服务器就会频繁地接收和发送请求图片,造成服务器请求压力过大,大大降低了页面的加载速度

  • 优化效果

    有效地减少了 HTTP 请求数量,提高了页面的加载速度

服务端策略响应

  • 核心思路

    在服务端代码中检测浏览器的 Accept 请求头,选择浏览器支持的最优的图片格式并返回。

  • 代码实现

    const accept = ctx.request.headers['accept']
    // 设置响应头,将响应图片的类型返回
    ctx.response.set('Content-Type', mimeType)