SVG vs Image, SVG vs Iconfont

这可能是个别人写过很多次的话题,但貌似由于兼容性的原因?图标的显示还是用着 Iconfont 或者 CSS Sprite 的形式?
希望通过自己新瓶装旧酒的方式能重新引导一下问题。

SVG vs Image

比方说现在要做下图这样的视觉效果:

SVG vs Image, SVG vs Iconfont_第1张图片

分析:可能需要三张图片

  1. 鼠标移入时的背景图
  2. 渐变色前景图
  3. 鼠标移入时白色前景图

独立图像

现在对比一下背景图使用图片与使用 SVG 格式的体积大小(做图的时候拿错颜色了,其他都一样,能说明道理就行,见谅见谅)

SVG vs Image, SVG vs Iconfont_第2张图片

可以看出,在肉眼感觉差异不大的情况下,WebP 格式体积最小,其次是 SVG,而 PNG 的体积过大。

这个 SVG 是在 Sketch 设计稿中导出来的,源码包含了很多冗余无效的代码,实际上是可以优化的,如下。

内部源码

SVG vs Image, SVG vs Iconfont_第3张图片

优化后

SVG vs Image, SVG vs Iconfont_第4张图片

优化后大约可以减去 1K 个字符。当然这个需要内联使用(Inline SVG)

SVG vs Image, SVG vs Iconfont_第5张图片

CSS Sprite

使用 CSS Sprite 的方式可以减少 HTTP 请求,貌似还可以减少总体图片体积。
这里用前景图来对比一下,实际上背景图和前景图都可以合成一张 sprite

SVG vs Image, SVG vs Iconfont_第6张图片

可以看出,CSS Sprite 的体积比 Inline SVG + CSS 的方式大很多。

SVG vs Image 结论

SVG vs Image, SVG vs Iconfont_第7张图片

绿色部分表示 SVGImage 略胜一筹的地方,黄色部分表示有所欠缺的地方,灰绿色表示差不多。

1、如今已接近 2019 年了,对于 IE9 (2011年) 这种古老的浏览器都支持 SVG,所以再过多强调更低的兼容性也没有什么意思。
2、Inline SVG 在浏览器应该是被渲染成 DOM 节点,所以关于 DOM 节点的性能优化都有必要注意;一个 SVG 图像可能就会有很多路径,即 DOM 节点,太多的 DOM 节点必然会影响浏览器的渲染性能及内存占用,而纯位图的渲染方式应该是没有这方面的顾虑。(DOM 数量影响参考:Google WEB 开发者文档

综上结论:

除开复杂图像,选择 Inline SVG 或者 标签的方式引入 SVG,会比使用 独立图像组合图像 (CSS sprite) 的方式更好。

SVG vs Iconfont

书写对比

首先看下 IconfontSVG 图标的使用方式,来源 阿里 Iconfont 平台

SVG vs Image, SVG vs Iconfont_第8张图片

很明显 SVG Sprite 使用起来没有 Iconfont 方便,需要写 3 行代码, 而后者只需要写 1 行。
当然上面的不是重点,重点是下面的换色与多色支持

换色与多色支持

换色

1、Iconfont 通过 CSS color 可以轻松更换图标颜色。

2、而 SVG Sprite 比较麻烦,SVG Sprite 的代码原理如下。

// 定义 symbol

    
      
    
    
      
    


// 使用

渲染出来的 DOM 结构是这样的:

SVG vs Image, SVG vs Iconfont_第9张图片

渲染在了 Shadow DOM 中(关于 Shadow DOM 的知识可以阅读下这篇文章这篇),
这样的 DOM 元素样式就具有了作用域,外面的 CSSshadow-root 内的元素不会生效,
如果想要更换元素的颜色,需要使用 /deep/ 来穿透添加样式,如下。

svg /deep/ path {
    fill: red;
}

当然,实际上在只需要在父级元素上添加 fill: red 这样的 CSS 也能起到同样的效果,里面的元素会继承父级的样式。

PS: /deep/shadow DOM v0 的写法,v1 已经把这样的写法抛弃了,实际上支持 v1shadow DOM, 父级的样式可以直接作用在 shadow-root 里面的元素。

多色支持

1、Iconfont 是不支持多色图标的。

2、而 SVG Sprite 可以利用 CSS 变量或 shadow DOM 的方式支持多色图标,shadow DOM 的方式上面已经说明,下面借用他人的文章解释 CSS 变量实现多色,如下。

SVG vs Image, SVG vs Iconfont_第10张图片

不过使用 CSS 变量或 shadow DOM 的方式兼容性都不好,

  1. CSS 变量:Edge15+
  2. shadow DOM:更差。兼容性列表

3、Inline SVG 可以良好地支持多色及多色变化。

渐变色支持

IconfontSVG Sprite 不支持渐变色。
Inline SVG 支持渐变色,并且兼容性良好。

渲染无抖动

使用 Iconfont,因为字体文件是异步加载的,所以在字体文件还没有加载完毕之前,图标位会留空,加载完毕后才会显示出来,这个过程就会出现向下图(来自 GitHub blog)这样的抖动,而 SVG Sprite Inline SVG 内联加载则不会出现这样的抖动。

SVG vs Image, SVG vs Iconfont_第11张图片

当然,Iconfont 也可以内联加载,不过需要转换成 base64 同样式表一起加载,转换后的文件体积则会变为原来的 1.3 倍左右
这是由 base64 编码决定的(编码知识链接)。

字体转换成 base64 的一个在线工具:https://transfonter.org/

体积较大

这个是 SVG 对比于 Iconfont 的一个不足之处,如下图。

SVG vs Image, SVG vs Iconfont_第12张图片

Inline SVGSVG 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 组件:







3、使用:



或者


  

SVG vs Iconfont 结论

应该是 Inline SVG vs SVG Sprite vs Iconfont 的结论,如下图。

SVG vs Image, SVG vs Iconfont_第13张图片

综上结论

选择 Inline SVG 或许是一个不错地选择去替代 Iconfont 的使用方式。

扩展阅读

  1. GitHub 网站很早之前已经将图标的展示方式由 Iconfont 转成了 Inline SVG, 这一篇文章是他们的描述:
    https://blog.github.com/2016-...
  2. 很早的一篇文章关于两者的对比:https://css-tricks.com/icon-f...

最后

欢迎各抒己见谈论一下对 SVGIconfont 的看法,优缺点,欢迎留言。

然后,本文同步发表于【凹凸实验室博客】或微信公众号,欢迎关注我们,么么哒。

clipboard.png

你可能感兴趣的:(SVG vs Image, SVG vs Iconfont)