这多是个别人写过不少次的话题,但貌似因为兼容性的缘由?图标的显示仍是用着 Iconfont
或者 CSS Sprite
的形式?
但愿经过本身新瓶装旧酒的方式能从新引导一下问题。javascript
比方说如今要作下图这样的视觉效果:css
分析:可能须要三张图片html
如今对比一下背景图使用图片与使用 SVG 格式的体积大小(作图的时候拿错颜色了,其余都同样,能说明道理就行,见谅见谅)vue
能够看出,在肉眼感受差别不大的状况下,WebP
格式体积最小,其次是 SVG
,而 PNG
的体积过大。 java
这个 SVG
是在 Sketch
设计稿中导出来的,源码包含了不少冗余无效的代码,其实是能够优化的,以下。git
内部源码github
优化后web
优化后大约能够减去 1K
个字符。固然这个须要内联使用(Inline SVG)浏览器
使用 CSS Sprite
的方式能够减小 HTTP
请求,貌似还能够减小整体图片体积。
这里用前景图来对比一下,实际上背景图和前景图均可以合成一张 sprite
。性能优化
能够看出,CSS Sprite
的体积比 Inline SVG + CSS
的方式大不少。
绿色部分表示 SVG
比 Image
略胜一筹的地方,黄色部分表示有所欠缺的地方,灰绿色表示差很少。
一、现在已接近 2019
年了,对于 IE9 (2011年)
这种古老的浏览器都支持 SVG
,因此再过多强调更低的兼容性也没有什么意思。
二、Inline SVG
在浏览器应该是被渲染成 DOM
节点,因此关于 DOM
节点的性能优化都有必要注意;一个 SVG
图像可能就会有不少路径,即 DOM
节点,太多的 DOM
节点必然会影响浏览器的渲染性能及内存占用,而纯位图的渲染方式应该是没有这方面的顾虑。(DOM
数量影响参考:Google WEB 开发者文档)
除开复杂图像,选择 Inline SVG
或者 <img/>
标签的方式引入 SVG
,会比使用 独立图像
或 组合图像 (CSS sprite)
的方式更好。
首先看下Iconfont
与SVG
图标的使用方式,来源 阿里 Iconfont 平台
很明显 SVG Sprite
使用起来没有 Iconfont
方便,须要写 3
行代码, 然后者只须要写 1
行。
固然上面的不是重点,重点是下面的换色与多色支持
一、Iconfont
经过 CSS color
能够轻松更换图标颜色。
二、而 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
里面的元素。
一、Iconfont
是不支持多色图标的。
二、而 SVG Sprite
能够利用 CSS
变量或 shadow DOM
的方式支持多色图标,shadow DOM
的方式上面已经说明,下面借用他人的文章解释 CSS
变量实现多色,以下。
不过使用 CSS
变量或 shadow DOM
的方式兼容性都很差,
CSS
变量:Edge15+shadow DOM
:更差。兼容性列表 三、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
便捷使用。
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 }, // ...其余参数 ] } } ] }
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 *[fill='none'] { fill none } *[stroke='none'] { stroke none } } } } </style> <style lang="stylus"> .svg-icon-hover { &:hover { svg { *[fill] { fill currentColor } *[stroke] { stroke currentColor } } } } </style>
<SvgIcon name="arrow-right" /> 或者 <a class="svg-icon-hover" href="#"> <SvgIcon name="arrow-right" /> </a>
应该是 Inline SVG vs SVG Sprite vs Iconfont
的结论,以下图。
选择 Inline SVG
或许是一个不错地选择去替代 Iconfont
的使用方式。
Iconfont
转成了 Inline SVG
, 这一篇文章是他们的描述:欢迎各抒己见谈论一下对 SVG
和 Iconfont
的见解,优缺点,欢迎留言。
而后,本文同步发表于【凹凸实验室博客】或微信公众号,欢迎关注咱们,么么哒。