SVG Sprite 简介

1024 7年前
   <h2><strong>前言</strong></h2>    <p>首页的高速加载和渲染一直是前端开发者们津津乐道的事情,因此各种技术也应运而生。在 HTTP1.1 时代,为了减少请求的发送,加快首页加载,压缩和合并成了必不可少的技术,其中包括了 JavaScript 文件的压缩、混淆和合并,还有 CSS 文件的压缩和合并,最后还有一个是针对小图片的请求优化,也就是 CSS Sprite ,也叫 雪碧图 或 CSS 精灵 。其大概的思想就是将多个小图片按照一定的尺寸和位置排列好,然后合成一张图片,最后用户访问页面时,只要请求这一张合成图,而开发者利用 background-position 等属性控制显示合成图某个位置的图片,即可达到一张图片多个图标的效果,同时也将请求数量压缩为一个。当然,这次我们要说的并不是这个技术,而是与之运用思想类似的 SVG Sprite 。</p>    <h2><strong>SVG Sprite</strong></h2>    <p>SVG Sprite 使用 <symbol> 标签来定义一个图形模板对象,好处在于其可以重复利用,我们可以看一下 MDN 中对 <symbol> 的定义:</p>    <p>symbol元素用来定义一个图形模板对象,它可以用一个 元素实例化。symbol元素对图形的作用是在同一文档中多次使用,添加结构和语义。结构丰富的文档可以更生动地呈现出来,类似讲演稿或盲文,从而提升了可访问性。注意,一个symbol元素本身是不呈现的。只有symbol元素的实例(亦即,一个引用了symbol的 元素)才能呈现。</p>    <p>可以看到, <symbol> 定义的图形并不会第一时间显示出来,只有使用了 <use> 标签进行实例化以后才会显现。 MDN 中对其做出了如下定义:</p>    <p>use元素在SVG文档内取得目标节点,并在别的地方复制它们。它的效果等同于这些节点被深克隆到一个不可见的DOM中,然后将其粘贴到use元素的位置,很像HTML5中的克隆模板元素。</p>    <p>而要使用 <use> 来实例化一个 svg图形模板对象 ,则要使用其中的 xlink:href 属性,在我们处理好的 <symbol> 上都会带有一个 id ,如下所示(伪代码):</p>    <pre>  <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></pre>    <p>根据每一个 <symbol> 的 id ,我们可以使用 <use> 根据这些 id 来使用 svg ,如下所示:</p>    <pre>  <div class="icons">      <svg><use xlink:href="#icon1"/></svg>    <svg><use xlink:href="#icon2"/></svg>    <svg><use xlink:href="#icon3"/></svg>  </div></pre>    <p>SVG Sprite 的基本原理就是运用这些元素,相比较 CSS Sprite , SVG Sprite 显得更为友好,不用多余的例如 background-position 属性来控制位置。</p>    <h2><strong>兼容性</strong></h2>    <p style="text-align: center;">运用一个技术的前提都是其兼容性满足项目的最低要求,或者在不兼容的情况下有相对应的替代方案。在饿了么 Web 的兼容性要求为 PC 端 IE9+,安卓移动端 4.4+,IOS7+,具体可以看 ElemeFE 的 <a href="/misc/goto?guid=4959722402605905235" rel="nofollow,noindex">style-guide</a> 。下面是在 <a href="/misc/goto?guid=4959722402708335122" rel="nofollow,noindex">caniuse</a> 上的结果: <img src="https://simg.open-open.com/show/4540d2588bdfa2d03b1ab6cc6cf22be9.jpg"></p>    <p>可以看到兼容性在 PC 端上是完全没有问题的,而在移动端上也能支持,所以可以安心地用起来了。</p>    <h2><strong>结合 Webpack 使用 SVG Sprite</strong></h2>    <p>我们使用 Webpack 来对多个分离的 SVG 文件进行自动化处理为合并好的多个 <symbol> ,并插入到 <body> 顶部。首先我们要对 webpack.config.js 进行配置。</p>    <p>首先看一下基本的文件目录结构:</p>    <pre>  ├── 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</pre>    <p>webpack.config.js</p>    <pre>  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>    <p>可以看到,配置文件中使用了 svg-sprite-loader 和 svgo-loader 对 svg 文件进行处理, svg-sprite-loader 的作用就是将多个 svg 文件合并为一个 <svg> 元素。至于 svgo-loader ,作用是将 <svg> 中一些无用的信息过滤去除,精简结构,详细配置可以自行查阅对应的文档说明,可以根据实际需求进行过滤。接下来将列出 index.css , index.js , index.html 的内容:</p>    <p>index.css</p>    <pre>  * {    box-sizing: border-box;  }    .icons svg {    width: 100px;    height: 100px;  }</pre>    <p>index.js</p>    <pre>  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>    <p>index.html</p>    <pre>  <!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></pre>    <p>以上就是主要的一些配置和内容,如果需要完整的项目,可以到我的 <a href="/misc/goto?guid=4959722402784631481" rel="nofollow,noindex">github</a> 下 clone 项目到你的本地进行构建。下面是构建后的网页效果和结构:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/0d226f1269ebcf3e882f8f03389213f9.jpg"></p>    <h2><strong>优点 & 缺点</strong></h2>    <p>优点: * 将多个请求压缩为无请求 * svg 对比 image 其屏幕适应性更好,任何分辨率都能达到高清效果 * svg 体积更小 * 每一个 <symbol> 都可以重复利用</p>    <p>缺点: * svg 不利于变动性大的图片,例如需要经常修改颜色 * 兼容性对于需要兼容 IE8- 的网站不好,需要对低版本浏览器有替代方案</p>    <p><strong>参考资料:</strong></p>    <p><a href="/misc/goto?guid=4959722402876032171" rel="nofollow,noindex">https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg</a> <a href="/misc/goto?guid=4959722402960292288" rel="nofollow,noindex">https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/symbol</a> <a href="/misc/goto?guid=4959722403041076547" rel="nofollow,noindex">https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/defs</a> <a href="/misc/goto?guid=4959722403124299230" rel="nofollow,noindex">https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/use</a></p>    <p> </p>    <p>来自:https://fe.ele.me/svg-sprite-jian-jie/</p>    <p> </p>