淺探前端圖片優化

william發表於2018-12-25

  效能優化是前端開發必不可少的一環,而圖片優化又是效能優化中必不可少的一環,但不知道有多少開發者在網頁的開發過程中會注意圖片的使用,圖片使用不當可能會導致網頁載入卡頓、網頁載入速度慢等問題,這篇文章將會將我以往對圖片的處理做個總結。

 不同格式圖片優劣對比

  有人可能會問說好的圖片優化呢?怎麼說到圖片格式了,其實在不同的場景選擇使用不同格式的圖片就是對圖片的一種優化,這是最直接最重要但是最容易被忽略的,現在網頁中常用的圖片格式有JPG.PNG.SVG.WebP等,接下來我們就來介紹它們有何優劣

  JPG

  JPG格式的圖片應該是使用場景最多的圖片的格式了,由於JPG格式採用了極其高效的壓縮演算法,使其能在壓縮50%甚至60%的情況下依舊可以保持不錯的圖片質量,因此在網站設計中使用類似背景圖,輪播圖等大圖時都會考慮使用JPG格式的圖片,但是JPG始終是有失真壓縮,在對線條感較強或者顏色比較豐富的圖片做人為壓縮時,可能會出現失真的情況,同時它也不支援透明度處理

  PNG

  PNG格式的圖片特點大家都知道,就是高保真無失真壓縮,當對圖片設計有較高要求時,首選PNG格式,顯示高清細膩,但是它也有明顯的問題就是體積過大

  SVG

  SVG格式圖片有個顯著特點就是它是可程式設計的,是基於xml語法的,同時作為向量圖,它可以無限放大而不變形,因此可以方便的對不同手機螢幕做自適應,相比於PNG和JPG它的體積更小,只有1kb甚至更小,但是它最大的缺陷就是渲染成本過高,因此我們在選擇一些小且色彩單一的圖示時可以考慮使用SVG格式的圖片,如圖

  一般情況下,我們會將SVG格式的圖片上傳到iconfont上,這樣不僅方便管理而且方便使用,同時iconfont上還有許多其他設計師設計的優秀小圖示可以直接拿來使用,是不是很方便呢?

  WebP與gif

  這兩兄弟我們一般都是用來展示動圖的,但是WebP也可以用來展示靜態圖片,WebP最大的優點就是無失真壓縮,體積小,但是瀏覽器支援太差,我們來看caniuse的資料:

  從圖上可以看到WebP格式在蘋果裝置和IE上基本不支援,因此瀏覽器的不支援是它的硬傷,因此在對動圖做展示的時候我們不得不選gif,即便它的體積很大,渲染開銷也大

 圖片優化方案

  圖片質量壓縮

  圖片壓縮應該是圖片優化時最常用的方案,因為很簡單,只需要將圖片上傳到tinypng或者智圖這類的線上壓縮圖片平臺,對圖片進行壓縮,就可以較小圖片質量

  雪碧圖

  雪碧圖經常用來將多個小圖示和成一張圖片,然後將合成的圖片當作背景圖片是使用,這樣可以減少圖片的網路請求,使用之前可能需要請求10個網路小圖示,而使用之後請求一個就可以搞定,我個人通常使用gopng這個網站線上生成,還可以自動生成對應的css程式碼

  base64

  將一個圖片地址進行base64編碼後會得到一串字串,將這個字元直接放到img的src屬性上,你會發現瀏覽器是可以識別這一串字元的,不需要傳送網路請求直接解析,這樣就可以達到減少網路請求的目的,但是base64編碼後的圖片質量比原圖圖片質量要大,因此也只會在一些質量較小的圖示類圖片上面使用,否則得不償失,常見使用base64編碼的方案就是webpack的url-loader,舉個例子:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192
            }
          }
        ]
      }
    ]
  }
}

  上面的這個配置就是把8k一下的通過url-loader進行base64編碼,轉換成一串DataUrl

  css替換簡單圖示

  這個優化方案應該都懂,其實就是在寫程式碼之前先考慮一下設計稿裡面的哪些內容是可以通過程式碼來實現的,能通過程式碼實現的儘量用程式碼實現,同時實現的時候多考慮繪製效能,能使用css3做GPU硬體加速的就儘量使用css3屬性,這些都能減少圖片使用而且不影響渲染效能

  響應式圖片載入

  什麼是響應式圖片載入?其實就是在不同解析度的裝置上顯示不同尺寸的圖片,避免資源的浪費,常用的方法就是css3的媒體查詢(media query),來看個例子:

@media screen and (max-width: 375px) {
  img {
    background-image: url('phone.png');
  }
}
@media screen and (max-width: 768px) {
  img {
    background-image: url('tablet.png');
  }
}

  懶載入

  圖片懶載入的目的就是為加快頁面載入速度而做的,為了不讓圖片一次全部載入出來,通過將圖片地址存放在一個img標籤的屬性上,當圖片被滾動到頁面上時,在將src屬性替換成圖片地址來達到懶載入的效果

  webpack圖片優化

  圖片壓縮

  webpack也可以對圖片進行壓縮操作,通過image-webpack-loader可以對輸出的圖片進行指定質量的壓縮,來看具體例子:

{
test: /\.(png|jpg|gif|svg)$/,
use: [
  'file-loader',
  {
    loader: 'image-webpack-loader',
    options: {
      bypassOnDebug: true,
      mozjpeg: {
        progressive: true,
        quality: 65
      },
      optipng: {
        enabled: false,
      },
      pngquant: {
        quality: '65-90',
        speed: 4
      },
      gifsicle: {
        interlaced: false,
      },
      // the webp option will enable WEBP
      webp: {
        enabled: false,
      },
      limit: 1,
      name: '[name].[ext]?[hash]'
    }
  }]
}

  上面的配置指定了各個格式的圖片的壓縮質量,並且通過hash編碼重新命名輸出

  合成雪碧圖

  webpack的webpack-spritesmith外掛提供了自動合成雪碧圖的功能並且可以自動生成對應的央視檔案,非常方便,來看一個具體的例子:

const SpritesmithPlugin = require('webpack-spritesmith')
new SpritesmithPlugin({
  src: {
    cwd: path.resolve(__dirname, 'src/asserts'),
    glob: '*.png'
  },
  target: {
    image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
    css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.css')
  },
  apiOptions: {
    cssImageRef: "src/sprite.png"
  }
})

  通過上面配置就能將asserts目錄下的所有png檔案合成雪碧圖,並且輸出到對應目錄,同時還可以生成對應的樣式檔案,樣式檔案的語法會根據你配置的樣式檔案的字尾動態生成,比如這裡我們配置的是sprite.css,生成的檔案內容就是css語法:

.icon-checkout {
  background-image: url(src/sprite.png);
  background-position: -96px -56px;
  width: 34px;
  height: 32px;
}
.icon-clock {
  background-image: url(src/sprite.png);
  background-position: -96px 0px;
  width: 56px;
  height: 56px;
}
.icon-close {
  background-image: url(src/sprite.png);
  background-position: 0px 0px;
  width: 96px;
  height: 96px;
}

  如果將配置中的sprite.css改成sprite.scss那麼生成語法就是scss的語法:

@mixin sprite-width($sprite) {
  width: nth($sprite, 5);
}

@mixin sprite-height($sprite) {
  height: nth($sprite, 6);
}

@mixin sprite-position($sprite) {
  $sprite-offset-x: nth($sprite, 3);
  $sprite-offset-y: nth($sprite, 4);
  background-position: $sprite-offset-x  $sprite-offset-y;
}

@mixin sprite-image($sprite) {
  $sprite-image: nth($sprite, 9);
  background-image: url(#{$sprite-image});
}

@mixin sprite($sprite) {
  @include sprite-image($sprite);
  @include sprite-position($sprite);
  @include sprite-width($sprite);
  @include sprite-height($sprite);
}
@mixin sprites($sprites) {
  @each $sprite in $sprites {
    $sprite-name: nth($sprite, 10);
    .#{$sprite-name} {
      @include sprite($sprite);
    }
  }
}

  這樣就可以根據你專案中使用的樣式語言去生成所需要的語法,是不是很方便呢?

 總結

  這篇文章簡單介紹網頁開發中的各個圖片格式的優缺和一些常用的圖片優化,希望這篇文章對大家以後在做圖片優化時能有所幫助。

相關文章