前端項目中的圖片可處理選擇

通常網頁的資源來講,圖片數量或者圖片體積都會在整個項目中佔據極大的比重,相比較代碼的處理,圖片處理顯得特別手段有限,可是利用的好能夠將用戶體驗提高上一個臺階css

響應式圖片

根據屏幕像素加載不一樣的圖片尺寸,優勢是自適應選擇圖片保持高清晰度,減小沒必要要的請求渲染時間,缺點是增長代碼量和項目體積.vue

媒體查詢

這是兼容性最好的方法,略顯繁瑣node

.bg { background-image: url(demo-320w.jpg); }
@media (min-device-pixel-ratio: 2){
    .bg { background-image: url(demo-640w.jpg); }
}

srcset

以逗號分隔的一個或多個字符串列表代表一系列用戶代理使用的可能的圖像。每個字符串由如下組成:webpack

  1. 指向圖像的 URL。
  2. 可選地,再加一個空格以後,附加如下的其一:git

    • 一個寬度描述符,這是一個正整數,後面緊跟 'w' 符號。該整數寬度除以sizes屬性給出的資源(source)大小來計算獲得有效的像素密度,即換算成和x描述符等價的值。
    • 一個像素密度描述符,這是一個正浮點數,後面緊跟 'x' 符號。
<img srcset="demo-320w.jpg,
             demo-480w.jpg 1.5x,
             demo-640w.jpg 2x"
     src="demo-default.jpg">

根據不一樣的像素密度加載不一樣的圖片,都不符合的狀況下會使用src做爲默認圖,這是用於像素密度的適配github

sizes

表示資源大小的、以逗號隔開的一個或多個字符串。每個資源大小包括:web

  1. 一個媒體條件。最後一項必定是被忽略的。
  2. 一個資源尺寸的值。
<img srcset="demo-320w.jpg,
             demo-480w.jpg 1.5x,
             demo-640w.jpg 2x"
     sizes="(max-width: 640px) 100vw,
            (max-width: 1080px) 33vw,
     src="demo-default.jpg">

表示圖片在640px及如下100%寬度,超過640px但1080px及如下33%寬度,這是用於屏幕寬度的適配 算法

下面是這兩個屬性的兼容圖api

srcset.png

picture + source

若是想要更加精確控制的話可使用這兩個新標籤瀏覽器

<picture>
  <source media="(max-width: 640px)" srcset="vertical.jpg">
  <source media="(min-width: 641px)" srcset="horizontal.jpg">
  <img src="default.jpg">
</picture>

media就至關於上面的sizes,這會從上往下判斷直到加載符合的資源.

source還有一個type屬性用於加載不一樣的圖片類型

<picture>
  <source type="image/svg" srcset="default.svg">
  <source type="image/webp" srcset="default.webp">
  <img src="default.jpg">
</picture>

下面是兼容性
picture.pngsource.png

tinypng壓縮

通常這一步應該是由Ui設計負責輸給到開發,也不排除部分UI沒有作這一步,咱們本身也能夠去作處理.

打開https://tinypng.com/選擇圖片...

壓縮效率

從圖片能夠看到根據以前圖片算法不一樣能夠壓縮的體積也不同,我隨便拿了兩張圖片測試就達到了10%67%.
0.png

對比

例子 格式 處理前 處理後 新舊體積比
圖一 jpg 189.3KB 165KB 87.1%
圖二 png 390KB 127KB 32.5%

未處理圖
1.png

跟原圖相比較,肉眼看不出畫質有損害
1_1.png

未處理圖
2.jpg

處理圖
2_1.jpg

imagemin-webpack-plugin

利用webpack插件對項目圖片進行壓縮處理,基本配置

import ImageminPlugin from 'imagemin-webpack-plugin'
import imageminMozjpeg from 'imagemin-mozjpeg'

module.exports = {
  plugins: [
    new ImageminPlugin({
      plugins: [
        imageminMozjpeg({
          quality: 65,
          progressive: true // 可將圖片轉成漸進式渲染,用戶體驗較好,可是渲染耗時更久
        })
      ]
    })
  ]
}

對比

例子 格式 處理前 處理後 新舊體積比
圖一 jpg 189.3KB 162KB 85.5%
圖二 png 390KB 94.2KB 24.1%

原圖
1.png

處理圖
1_2.png

原圖
2.jpg

處理圖94.2KB,比上面壓縮工具更優秀,畫質依然看不太出區別
2_2.jpg

webP

WebP最初在2010年發佈,目標是減小文件大小,但達到和JPEG格式相同的圖片質量,但願可以減小圖片檔在網絡上的發送時間。2011年11月8日,Google開始讓WebP支持無損壓縮和透明色(alpha通道)的功能,而在2012年8月16日的參考實作libwebp 0.2.0中正式支持。根據Google較早的測試,WebP的無損壓縮比網絡上找到的PNG檔少了45%的文件大小,即便這些PNG檔在使用pngcrush和PNGOUT處理過,WebP仍是能夠減小28%的文件大小。
webp.png

從安卓4.2開始也支持,只要兼容代碼寫得好也足以讓項目體積大大減小,safari暫時還不支持,可是也有手段能夠支持.

對比

例子 格式 處理前 處理後 新舊體積比
圖一 jpg 189.3KB 116KB 61.2%
圖二 png 390KB 165KB 42.3%

(不知道爲何沒有辦法上傳webp,因此就不放對比圖了)

CDN圖片處理

CDN除了緩存資源之外,還提供了不少額外處理工具,例如圖片轉換
cdn.png

這是一種更完善的方案,花錢解決各類處理保存轉換的難度和工做量,具體API大同小異.

雪碧圖

將多個圖片合併成一張大圖,能夠用一個請求拿到所需的圖片,而且合併後的體積比合並前的整體積還小,缺點是隻能使用背景而且須要定位位置,也能夠經過一些插件自動生成樣式.

在線生成sprite-generator

sprites.png

這種很是智能並且方便,可是不適用長期維護或者改動頻繁的項目

webpack-spritesmith

Webpack plugin that converts set of images into a spritesheet and SASS/LESS/Stylus mixins, using spritesmith and spritesheet-templates

示例配置

//webpack.config.js
var path = require('path');

var SpritesmithPlugin = require('webpack-spritesmith');

module.exports = {
    // ...
    module: {
        rules: [
            {test: /\.styl$/, use: [
                'style-loader',
                'css-loader',
                'stylus-loader'
            ]},
            {test: /\.png$/, use: [
                'file-loader?name=i/[hash].[ext]'
            ]}
        ]
    },
    resolve: {
        modules: ["node_modules", "spritesmith-generated"]
    },
    plugins: [
        new SpritesmithPlugin({
            src: {
                cwd: path.resolve(__dirname, 'src/ico'),
                glob: '*.png'
            },
            target: {
                image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
                css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl')
            },
            apiOptions: {
                cssImageRef: "~sprite.png"
            }
        })
    ]
    // ...
};

在項目開發中直接配置webpack會更加方便,更多配置可查看倉庫

base64

用webpack的基本入門庫能夠簡單實現, url-loader 功能相似於 file-loader,可是在文件大小(單位 byte)低於指定的限制時,能夠返回一個 DataURL。

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

只適用於小圖片的轉換,原理就是經過增長代碼量來減小資源請求,因此控制轉換的體積限制尤其重要,並且自己的問題也很多

例子

base64.png

優勢:

  • 減小資源請求數
  • 不受瀏覽器併發數限制沒有沒必要要的阻塞時間
  • 瀏覽器兼容性好

缺點:

  • 編碼體積是原數據體積的4/3左右,且大量使用下降代碼可觀性
  • 瀏覽器不會緩存Data URL圖片
  • CPU資源更多
  • 內存消耗更大
  • 渲染耗時更長

SVG

svg.png

與其餘圖像格式相比,使用 SVG 的優點在於:

  • SVG 可被很是多的工具讀取和修改(好比記事本)
  • SVG 與 JPEG 和 GIF 圖像比起來,尺寸更小,且可壓縮性更強。
  • SVG 是可伸縮的
  • SVG 圖像可在任何的分辨率下被高質量地打印
  • SVG 可在圖像質量不降低的狀況下被放大
  • SVG 圖像中的文本是可選的,同時也是可搜索的(很適合製做地圖)
  • SVG 能夠與 Java 技術一塊兒運行
  • SVG 是開放的標準
  • SVG 文件是純粹的 XML

Vue項目引入

建立SvgIcon組件

<template>
  <svg :class="svgClass" aria-hidden="true">
    <use :xlink:href="iconName"></use>
  </svg>
</template>

<script>
export default {
  name: 'svg-icon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String
    }
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    }
  }
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

建立icons文件夾

import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg組件

// 註冊到全局
Vue.component('svg-icon', SvgIcon)

const requireAll = requireContext => requireContext.keys().map(requireContext)
// eslint-disable-next-line
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)

在main.js中引入

import './icons'

使用

<svg-icon icon-class="user" />

SVG sprite loader

Webpack loader for creating SVG sprites.

{
    test: /\.svg$/,
    loader: 'svg-sprite-loader',
    include: [resolve('src/icons')],
    options: {
        symbolId: 'icon-[name]'
    }
}
-------------------------------------------
exclude: [resolve('src/icons')],

SVG在線壓縮合並工具

具體參考張鑫旭博客SVG精簡壓縮工具svgo簡介和初體驗

字體圖標

上面說的全部方式終究仍是圖片或者會有某些損耗,而字體圖標是以字體形式展現圖標

阿里矢量圖標庫

iconfont.png

應用代碼有幾種,目前官方推薦方式是

unicode引用

unicode是字體在網頁端最原始的應用方式,特色是:

  • 兼容性最好,支持ie6+,及全部現代瀏覽器。
  • 支持按字體的方式去動態調整圖標大小,顏色等等。
  • 可是由於是字體,因此不支持多色。只能使用平臺裏單色的圖標,就算項目裏有多色圖標也會自動去色。

第一步:拷貝項目下面生成的font-face

@font-face {font-family: 'iconfont';
    src: url('iconfont.eot');
    src: url('iconfont.eot?#iefix') format('embedded-opentype'),
    url('iconfont.woff') format('woff'),
    url('iconfont.ttf') format('truetype'),
    url('iconfont.svg#iconfont') format('svg');
}

第二步:定義使用iconfont的樣式

.iconfont{
    font-family:"iconfont" !important;
    font-size:16px;font-style:normal;
    -webkit-font-smoothing: antialiased;
    -webkit-text-stroke-width: 0.2px;
    -moz-osx-font-smoothing: grayscale;}

第三步:挑選相應圖標並獲取字體編碼,應用於頁面

<i class="iconfont">&#x33;</i>

font-class引用

font-class是unicode使用方式的一種變種,主要是解決unicode書寫不直觀,語意不明確的問題。

與unicode使用方式相比,具備以下特色:

  • 兼容性良好,支持ie8+,及全部現代瀏覽器。
  • 相比於unicode語意明確,書寫更直觀。能夠很容易分辨這個icon是什麼。
  • 由於使用class來定義圖標,因此當要替換圖標時,只須要修改class裏面的unicode引用。
  • 不過由於本質上仍是使用的字體,因此多色圖標仍是不支持的。

第一步:拷貝項目下面生成的fontclass代碼:

//at.alicdn.com/t/font_8d5l8fzk5b87iudi.css

第二步:挑選相應圖標並獲取類名,應用於頁面:

<i class="iconfont icon-xxx"></i>

symbol引用

這是一種全新的使用方式,應該說這纔是將來的主流,也是平臺目前推薦的用法。相關介紹能夠參考這篇文章 這種用法實際上是作了一個svg的集合,與上面兩種相比具備以下特色:

  • 支持多色圖標了,再也不受單色限制。
  • 經過一些技巧,支持像字體那樣,經過font-size,color來調整樣式。
  • 兼容性較差,支持 ie9+,及現代瀏覽器。
  • 瀏覽器渲染svg的性能通常,還不如png。

第一步:拷貝項目下面生成的symbol代碼:

//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js

第二步:加入通用css代碼(引入一次就行):

<style type="text/css">
    .icon {
       width: 1em; height: 1em;
       vertical-align: -0.15em;
       fill: currentColor;
       overflow: hidden;
    }
</style>

第三步:挑選相應圖標並獲取類名,應用於頁面:

<svg class="icon" aria-hidden="true">
    <use xlink:href="#icon-xxx"></use>
</svg>

懶加載

這個是比較老生常談的手段了,從JQ時代開始就已經有比較豐富的經驗,到了框架時代,若是用Vue的話我知道的就有

vue-lazyload

功能比較強大

  • 輕量級、強大且易於使用
  • 可做用在任何類型的圖像
  • 在加載圖像時添加加載類
  • 同時支持Vue 1.0和Vue 2.0

引入模塊

import Vue from 'vue'
import App from './App.vue'
import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload)

// or with options
Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'dist/error.png',
  loading: 'dist/loading.gif',
  attempt: 1
})

new Vue({
  el: 'body',
  components: {
    App
  }
})

使用方法

可自定義加載和錯誤圖

<div v-lazy-container="{ selector: 'img', error: 'xxx.jpg', loading: 'xxx.jpg' }">
  <img data-src="//domain.com/img1.jpg">
  <img data-src="//domain.com/img2.jpg">
  <img data-src="//domain.com/img3.jpg">  
</div>
// 或者
<div v-lazy-container="{ selector: 'img' }">
  <img data-src="//domain.com/img1.jpg" data-error="xxx.jpg">
  <img data-src="//domain.com/img2.jpg" data-loading="xxx.jpg">
  <img data-src="//domain.com/img3.jpg">  
</div>

預加載

一次性加載完圖片再開始渲染界面

簡單實現

<script>
export default {
  data () {
    return {
      count: 0,
    }
  },
  mounted: function() {
    this.preload()
  },
  methods: {
    preload: function() {
      const imgs = ['xxx.png', ...]

      for (let img of imgs) {
        const image = new Image()
        image.src = img
        image.onload = () => {
          this.count++
        }
      }

    },
  },
}
</script>
相關文章
相關標籤/搜索