SVG Sprite 簡介
前言
首頁的高速加載和渲染一直是前端開發者們津津樂道的事情,因此各種技術也應運而生。在 HTTP1.1 時代,為了減少請求的發送,加快首頁加載,壓縮和合并成了必不可少的技術,其中包括了 JavaScript 文件的壓縮、混淆和合并,還有 CSS 文件的壓縮和合并,最后還有一個是針對小圖片的請求優化,也就是 CSS Sprite ,也叫 雪碧圖 或 CSS 精靈 。其大概的思想就是將多個小圖片按照一定的尺寸和位置排列好,然后合成一張圖片,最后用戶訪問頁面時,只要請求這一張合成圖,而開發者利用 background-position 等屬性控制顯示合成圖某個位置的圖片,即可達到一張圖片多個圖標的效果,同時也將請求數量壓縮為一個。當然,這次我們要說的并不是這個技術,而是與之運用思想類似的 SVG Sprite 。
SVG Sprite
SVG Sprite 使用 <symbol> 標簽來定義一個圖形模板對象,好處在于其可以重復利用,我們可以看一下 MDN 中對 <symbol> 的定義:
symbol元素用來定義一個圖形模板對象,它可以用一個 元素實例化。symbol元素對圖形的作用是在同一文檔中多次使用,添加結構和語義。結構豐富的文檔可以更生動地呈現出來,類似講演稿或盲文,從而提升了可訪問性。注意,一個symbol元素本身是不呈現的。只有symbol元素的實例(亦即,一個引用了symbol的 元素)才能呈現。
可以看到, <symbol> 定義的圖形并不會第一時間顯示出來,只有使用了 <use> 標簽進行實例化以后才會顯現。 MDN 中對其做出了如下定義:
use元素在SVG文檔內取得目標節點,并在別的地方復制它們。它的效果等同于這些節點被深克隆到一個不可見的DOM中,然后將其粘貼到use元素的位置,很像HTML5中的克隆模板元素。
而要使用 <use> 來實例化一個 svg圖形模板對象 ,則要使用其中的 xlink:href 屬性,在我們處理好的 <symbol> 上都會帶有一個 id ,如下所示(偽代碼):
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0;visibility:hidden"> <defs> <symbol id="icon1">...</symbol> <symbol id="icon2">...</symbol> <symbol id="icon3">...</symbol> </defs> </svg>
根據每一個 <symbol> 的 id ,我們可以使用 <use> 根據這些 id 來使用 svg ,如下所示:
<div class="icons"> <svg><use xlink:href="#icon1"/></svg> <svg><use xlink:href="#icon2"/></svg> <svg><use xlink:href="#icon3"/></svg> </div>
SVG Sprite 的基本原理就是運用這些元素,相比較 CSS Sprite , SVG Sprite 顯得更為友好,不用多余的例如 background-position 屬性來控制位置。
兼容性
運用一個技術的前提都是其兼容性滿足項目的最低要求,或者在不兼容的情況下有相對應的替代方案。在餓了么 Web 的兼容性要求為 PC 端 IE9+,安卓移動端 4.4+,IOS7+,具體可以看 ElemeFE 的 style-guide 。下面是在 caniuse 上的結果:
可以看到兼容性在 PC 端上是完全沒有問題的,而在移動端上也能支持,所以可以安心地用起來了。
結合 Webpack 使用 SVG Sprite
我們使用 Webpack 來對多個分離的 SVG 文件進行自動化處理為合并好的多個 <symbol> ,并插入到 <body> 頂部。首先我們要對 webpack.config.js 進行配置。
首先看一下基本的文件目錄結構:
├── LICENSE ├── README.md ├── css │ └── index.css ├── dist │ ├── app.css │ ├── app.js │ └── index.html ├── js │ └── index.js ├── package.json ├── static │ ├── analytics.svg │ ├── archives.svg │ ├── businessman.svg │ ├── businessmen.svg │ ├── certificate.svg │ ├── chat.svg │ └── contract.svg ├── template │ └── index.html └── webpack.config.js
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');var plugins = [
new HtmlWebpackPlugin({ filename: './index.html', template: './template/index.html' }) ];plugins.push(
new ExtractTextPlugin('[name].css') );module.exports = {
entry: { app: './js/index.js', },output: { path: './dist', publicPath: './', // filename: '[name].[chunkhash:6].js' filename: '[name].js' },
resolve: { extensions: [ '', '.js' ] },
module: { loaders: [ { test: /.js$/, exclude: /node_modules/, loader: 'babel-loader' }, { test: /.css$/, loader: ExtractTextPlugin.extract('style', 'css') }, { test: /.svg$/, loaders: [ 'svg-sprite-loader', 'svgo-loader?useConfig=svgoConfig' ] }, { test: /.(gif|png|jpg|ttf|woff2|woff|eot)$/, loader: 'url?limit=1000&name=[path][name].[hash:6].[ext]' } ] },
svgoConfig: { plugins: [ { removeTitle: true }, { convertColors: { shorthex: true } }, { convertPathData: true }, { cleanupAttrs: true }, { removeComments: true }, { removeDesc: true }, { removeUselessDefs: true }, { removeEmptyAttrs: true }, { removeHiddenElems: true }, { removeEmptyText: true } ] }, plugins: plugins };</pre>
可以看到,配置文件中使用了 svg-sprite-loader 和 svgo-loader 對 svg 文件進行處理, svg-sprite-loader 的作用就是將多個 svg 文件合并為一個 <svg> 元素。至于 svgo-loader ,作用是將 <svg> 中一些無用的信息過濾去除,精簡結構,詳細配置可以自行查閱對應的文檔說明,可以根據實際需求進行過濾。接下來將列出 index.css , index.js , index.html 的內容:
index.css
- { box-sizing: border-box; }
.icons svg { width: 100px; height: 100px; }</pre>
index.js
import indexStyle from '../css/index.css';
import analytics from '../static/analytics.svg'
import archives from '../static/archives.svg'
import businessman from '../static/businessman.svg'
import businessmen from '../static/businessmen.svg'
import certificate from '../static/certificate.svg'
import chat from '../static/chat.svg'
import contract from '../static/contract.svg'console.log('demo complete');</pre>
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>svg-sprites-demo</title> </head> <body> <div class="icons"> <svg><use xlink:href="#analytics"/></svg> <svg><use xlink:href="#archives"/></svg> <svg><use xlink:href="#businessman"/></svg> <svg><use xlink:href="#businessmen"/></svg> <svg><use xlink:href="#certificate"/></svg> <svg><use xlink:href="#chat"/></svg> <svg><use xlink:href="#contract"/></svg> </div> </body> </html>以上就是主要的一些配置和內容,如果需要完整的項目,可以到我的 github 下 clone 項目到你的本地進行構建。下面是構建后的網頁效果和結構:
優點 & 缺點
優點: * 將多個請求壓縮為無請求 * svg 對比 image 其屏幕適應性更好,任何分辨率都能達到高清效果 * svg 體積更小 * 每一個 <symbol> 都可以重復利用
缺點: * svg 不利于變動性大的圖片,例如需要經常修改顏色 * 兼容性對于需要兼容 IE8- 的網站不好,需要對低版本瀏覽器有替代方案
參考資料:
https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/symbol https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/defs https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/use
來自:https://fe.ele.me/svg-sprite-jian-jie/