SVG Sprite 简介
1024
8年前
<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>