web性能-图片优化

1,093 阅读5分钟

web性能-图片优化

基本优化

加快请求

  1. 利用CDN(一次加载,长效缓存,静态资源都可以放cdn)
  2. 图片压缩
    1. 在线网站 TinyPNG
    2. image-webpack-loader(会导致webpack打包时间变长)

减少请求

  1. http/1.x的话,为了减少请求可以用雪碧图。http2可以不用雪碧图,对缓存不友好
  2. 小图标尽量用字体图标(也类似雪碧图,把所有的图标以文件的格式,一次性返回)

延迟请求

  1. 图片的懒加载

    (懒加载的库很多,选择一个最小的 lazyestload.js ,压缩后0.4kb左右,能满足基本需求)

    • 原理是用了 IntersectionObserver (当dom元素与视口交叉的时,触发事件)
    <img class="lazyestload" 
         src="images/placeholder/sunset.jpg" 
         data-srcset="images/sunset-400.jpg 400w, images/sunset.jpg 1600w" >
    
    • 还可以通过使用标签的解决方案,为关闭了JavaScript的用户做打算。

      <picture>
          <source data-srcset="img/chicken-marsala-2x.webp 2x, img/chicken-marsala-1x.webp 1x" type="image/webp">
          <source data-srcset="img/chicken-marsala-2x.jpg 2x, img/chicken-marsala-1x.jpg 1x" type="image/jpeg">
          <img src="img/blank.png" data-src="img/chicken-marsala-1x.jpg" class="recipeImage lazy">
      </picture>
            
      关闭了js的用户,就没有懒加载功能,只能直接加载图像了
      <noscript>
          <picture>
              <source srcset="img/chicken-marsala-2x.webp 2x, img/chicken-marsala-1x.webp 1x" type="image/webp">
              <source srcset="img/chicken-marsala-2x.jpg 2x, img/chicken-marsala-1x.jpg 1x" type="image/jpeg">
              <img src="img/chicken-marsala-1x.jpg" class="recipeImage">
          </picture>
      </noscript>
      

    另外还推荐一个开源库:lozad.js,www.npmjs.com/package/loz…

    • 用起来还不错,体积也不大,gzip后 1kb+
    • 功能比上面的更全,除了<img 外, video 等 也能支持

    最后,要上手的话, 建议先最小单元模块测试 跑通三方库的使用,在用到项目内去。

图片类型优化

目的:用更高效的格式webp

矢量图:svg(是计算出来的,缩放不失真)

位图:JPEG,PNG,GIF,WebP(像素级)

WebP优化的最好。同样图片效果,WebP体积最小

但需要注意3个使用问题:

  1. WebP如何做兼容?

    1. 可以结合使用<picture>元素与<source>元素的type属性,为不支持WebP的浏览器指定已有的图像类型回退

      <picture>
        <source srcset='img/xx-small.webp' type="image/webp">
        <img src="img/xx-small.jpg">
      </picture>
      

      <picture>标签的兼容性

      image.png

      • 不支持<picture> 标签的话,需要polyfill

        1. 有损WebP版本代替JPEG,无损WebP版本代替PNG。
    2. 另外还可以用js的方法来兼容

      可以结合图片懒加载组件,一起写。可能会比上面的更简单

      /**
       *  判断当前浏览器是否支持webp
       */
      let bool: boolean
      export function isSupportWebp() {
        if (bool !== undefined) {
          return bool
        } else {
          try {
            // Boolean([].map) 主要是判断浏览器是否为 IE9+ ,以免 toDataURL 方法会挂掉;
            // 如果你直接对数组原型扩展了 map 方法,则需要使用 !![].map 以外的方法进行判断 ,例如  !!window.addEventListener 等;
            bool =
              Boolean([].map) &&
              document
                ?.createElement('canvas')
                ?.toDataURL('image/webp')
                ?.startsWith('data:image/webp')
            return bool
          } catch (err) {
            return false
          }
        }
      }
      

    2022.7.18补充,上面的方法,在safari上会失效(safari能支持webp,上面也会返回false),推荐用:

    let support = true
    export function isSupportWebp() {
      if (typeof window === 'undefined') {
        // 服务端, 默认用webp
        return true
      }
      if (support !== undefined) {
        return support
      }
      try {
        const el = document.createElement('object')
        el.type = 'image/webp'
        el.style.visibility = 'hidden'
        el.innerHTML = '!'
        document.body.appendChild(el)
        support = !el.offsetWidth
        document.body.removeChild(el)
      } catch (err) {
        support = false
      }
    
      return support
    }
    
  2. webpack如何解析 webp格式 的资源?

    2c 场景我们加载图片一般是用CDN。但一些内部项目想尝试webpack解析webp的话:

    使用 file-loader(实际就是处理资源引入的path)

    ...
    {
      test: /\.(webp)$/i,
      loader: 'file-loader'
    },
    ...
    
  3. webp格式 压缩效果

    公司内部没有基建的话,开源的有:webp压缩网站:www.upyun.com/webp tinypng压缩图片:tinypng.com/

    个人亲测了2张图片

    体积大小图片效果
    原图98.9kb原图
    webp57.6kb细节略微一点点模糊
    tinypng87.0kb几乎无损
    体积大小图片效果
    原图262.5kb原图
    webp24.8kb细节略微一点点模糊
    tinypng52.7kb几乎无损

总结:webp的对图片的压缩效率非常高,画质接近几乎无损,十分建议使用

响应式图像优化

(为不同的尺寸,准备不同的图片大小)

背景举例:

  • 同样一张图。pc端是大图1Mb,移动端只需300kb的小图就够了
    • 比如 1920x1080的图片,在pc端展示ok,但响应到移动端之后(假设移动端是750x1334),此时就需要缩放图像,宽度成750。 如果能在响应成移动端时,直接把图片也换成成宽度750的,文件也会更小,更高效(用控制台的performance可以测试,响应时间和渲染时间都会更短)

具体操作:

  1. css:媒体查询:background-image: url("../img/xxx-small.png(或svg)")

  2. html:<picture>元素和<img>标签的srcset属性,不兼容的话 还需polyfill

    1. 对图片需设置一个通用的配置:

      1. img { max-width: 100%; } (好处:使图片都渲染成为自然宽度。除非超过容器宽度,超过时,会限制图片最大宽度是容器宽度)
    2. srcset(html5 出的 显示响应式图像)(效果类似媒体查询)

         <img src='img-small.jpg' 
              srcset="img-medium.jpg 640w, 
                      img-large.jpg 1280w">
         如果不支持srcset,则直接读取 src,此处默认移动优先
      
    3. sizes可以更细的控制图片的宽度:比如在宽屏时 图片占一半宽度50vw

         <img src='img-small.jpg' 
              srcset="img-medium.jpg 640w, 
                      img-large.jpg 1280w"
              sizes="(min-width: 704px) 50vw, 
                     (min-width: 480px) 75vw, 
                     100vw" >
      

渐进式图片

效果(渐进式图片的体验要好一些):

一般线性加载: image.png

交错/渐进式: image.png

如何得到渐进式图片:

gif动图优化

gif图片不处理的话,体积会比较大。

常见的gif优化有2点:

  1. gif抽帧
    • gif 1秒有24帧(24张图片), 我们可以尝试抽成 8帧、12帧或16帧,具体还看场景
  2. 压缩
    • 本质也是压缩图片,可以转成webp格式

码字不易,点赞鼓励!

部分参考《Web性能实战》[美]杰里米·瓦格纳


性能优化合集快速入口: