这可能是个别人写过很多次的话题,但貌似由于兼容性的原因?图标的显示还是用着 Iconfont 或者 CSS Sprite 的形式?希望通过自己新瓶装旧酒的方式能重新引导一下问题。SVG vs Image比方说现在要做下图这样的视觉效果:分析:可能需要三张图片鼠标移入时的背景图渐变色前景图鼠标移入时白色前景图独立图像现在对比一下背景图使用图片与使用 SVG 格式的体积大小(做图的时候拿错颜色了,其他都一样,能说明道理就行,见谅见谅)可以看出,在肉眼感觉差异不大的情况下,WebP 格式体积最小,其次是 SVG,而 PNG 的体积过大。 这个 SVG 是在 Sketch 设计稿中导出来的,源码包含了很多冗余无效的代码,实际上是可以优化的,如下。内部源码优化后优化后大约可以减去 1K 个字符。当然这个需要内联使用(Inline SVG)CSS Sprite使用 CSS Sprite 的方式可以减少 HTTP 请求,貌似还可以减少总体图片体积。这里用前景图来对比一下,实际上背景图和前景图都可以合成一张 sprite。可以看出,CSS Sprite 的体积比 Inline SVG + CSS 的方式大很多。SVG vs Image 结论绿色部分表示 SVG 比 Image 略胜一筹的地方,黄色部分表示有所欠缺的地方,灰绿色表示差不多。1、如今已接近 2019 年了,对于 IE9 (2011年) 这种古老的浏览器都支持 SVG,所以再过多强调更低的兼容性也没有什么意思。2、Inline SVG 在浏览器应该是被渲染成 DOM 节点,所以关于 DOM 节点的性能优化都有必要注意;一个 SVG 图像可能就会有很多路径,即 DOM 节点,太多的 DOM 节点必然会影响浏览器的渲染性能及内存占用,而纯位图的渲染方式应该是没有这方面的顾虑。(DOM 数量影响参考:Google WEB 开发者文档)综上结论:除开复杂图像,选择 Inline SVG 或者 <img/> 标签的方式引入 SVG,会比使用 独立图像 或 组合图像 (CSS sprite) 的方式更好。SVG vs Iconfont书写对比首先看下 Iconfont 与 SVG 图标的使用方式,来源 阿里 Iconfont 平台很明显 SVG Sprite 使用起来没有 Iconfont 方便,需要写 3 行代码, 而后者只需要写 1 行。当然上面的不是重点,重点是下面的换色与多色支持换色与多色支持换色1、Iconfont 通过 CSS color 可以轻松更换图标颜色。2、而 SVG Sprite 比较麻烦,SVG Sprite 的代码原理如下。// 定义 symbol<svg> <symbol id=“icon-arrow-left” viewBox=“0 0 1024 1024”> <path d=“M694 … 44.576-45.952”></path> </symbol> <symbol id=“icon-arrow-right” viewBox=“0 0 1024 1024”> <path d=“M693 … 0-0.48-46.4”></path> </symbol></svg>// 使用<svg><use xlink:href="#icon-arrow-left"/></svg><svg><use xlink:href="#icon-arrow-right"/></svg>渲染出来的 DOM 结构是这样的:渲染在了 Shadow DOM 中(关于 Shadow DOM 的知识可以阅读下这篇文章或这篇),这样的 DOM 元素样式就具有了作用域,外面的 CSS 对 shadow-root 内的元素不会生效,如果想要更换元素的颜色,需要使用 /deep/ 来穿透添加样式,如下。svg /deep/ path { fill: red;}当然,实际上在只需要在父级元素上添加 fill: red 这样的 CSS 也能起到同样的效果,里面的元素会继承父级的样式。PS: /deep/ 是 shadow DOM v0 的写法,v1 已经把这样的写法抛弃了,实际上支持 v1 的 shadow DOM, 父级的样式可以直接作用在 shadow-root 里面的元素。多色支持1、Iconfont 是不支持多色图标的。2、而 SVG Sprite 可以利用 CSS 变量或 shadow DOM 的方式支持多色图标,shadow DOM 的方式上面已经说明,下面借用他人的文章解释 CSS 变量实现多色,如下。不过使用 CSS 变量或 shadow DOM 的方式兼容性都不好,CSS 变量:Edge15+shadow DOM:更差。兼容性列表3、Inline SVG 可以良好地支持多色及多色变化。渐变色支持Iconfont 与 SVG Sprite 不支持渐变色。Inline SVG 支持渐变色,并且兼容性良好。渲染无抖动使用 Iconfont,因为字体文件是异步加载的,所以在字体文件还没有加载完毕之前,图标位会留空,加载完毕后才会显示出来,这个过程就会出现向下图(来自 GitHub blog)这样的抖动,而 SVG Sprite 或 Inline SVG 内联加载则不会出现这样的抖动。当然,Iconfont 也可以内联加载,不过需要转换成 base64 同样式表一起加载,转换后的文件体积则会变为原来的 1.3 倍左右这是由 base64 编码决定的(编码知识链接)。字体转换成 base64 的一个在线工具:https://transfonter.org/体积较大这个是 SVG 对比于 Iconfont 的一个不足之处,如下图。Inline SVG 与 SVG Sprite 体积差不多。开发成本三者的开发成本都差不多,不过 SVG 的两种方式都需要前期做些配置,后期开发就会顺手很多(单页应用)。以 vue + vue cli 为例说明 Inline SVG 便捷使用。1、 配置 Webpack loader:{ // 排除需要转换成 Inline SVG 的目录 exclude: [resolve(‘src/svgicons’)], test: /.(png|jpe?g|gif|svg)(?.*)?$/, loader: ‘url-loader’, options: { limit: 1, name: utils.assetsPath(‘img/[name].[hash:7].[ext]’) }},{ // 指定特定的目录用于 Inline SVG include: [resolve(‘src/svgicons’)], test: /.svg$/, use: [ // 读取 SVG 源代码 { loader: ‘raw-loader’ }, // 精简优化 SVG 源代码 { loader: ‘svgo-loader’, options: { plugins: [ { removeTitle: true }, { removeViewBox: false }, { removeDimensions: true }, // …其他参数 ] } } ]}2、 创建 SvgIcon.vue 组件:<template> <div class=“svg-icon”> <div class=“svg-icon-wrapper” v-html=“icon”></div> </div></template><script>export default { name: ‘SvgIcon’, props: { name: { type: String, required: true, }, }, data () { return { icon: this.getIcon(), } }, watch: { name () { this.icon = this.getIcon() }, }, methods: { getIcon () { return require(@/svgicons/${this.name}.svg) }, },}</script><style lang=“stylus” scoped>.svg-icon { overflow hidden display inline-block width 1em height 1em &-wrapper { display flex align-items center >>> svg { width 100% height 100% fill currentColor } }}</style>3、使用:<SvgIcon name=“arrow-right” />SVG vs Iconfont 结论应该是 Inline SVG vs SVG Sprite vs Iconfont 的结论,如下图。综上结论选择 Inline SVG 或许是一个不错地选择去替代 Iconfont 的使用方式。扩展阅读GitHub 网站很早之前已经将图标的展示方式由 Iconfont 转成了 Inline SVG, 这一篇文章是他们的描述:https://blog.github.com/2016-…很早的一篇文章关于两者的对比:https://css-tricks.com/icon-f…最后欢迎各抒己见谈论一下对 SVG 和 Iconfont 的看法,优缺点,欢迎留言。然后,本文同步发表于【凹凸实验室博客】或微信公众号,欢迎关注我们,么么哒。