SVG Sprite 簡介

1024 8年前發布 | 13K 次閱讀 SVG 前端技術

前言

首頁的高速加載和渲染一直是前端開發者們津津樂道的事情,因此各種技術也應運而生。在 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/

 

 本文由用戶 1024 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!