编者按:本文由花裤衩发表于掘金,作者已授权分享到奇舞周刊。
前言
本篇文章其实陆陆续续写了快半年,主体部分写好了很久了,但由于种种原因一直没有发布。
首先来说说写这篇文章的主要初衷是:在做前端后台项目的时候经常会用到很多 icon 图标,刚开始还好,但随着项目的不断迭代,每次修改添加图标会变得很麻烦,而且总觉得不够优雅,就开始琢磨着有啥简单方便的工作流呢?
演进史
首先我们来说一下前端 icon 的发展史。
远古时代
在我刚开始实习时,大部分图标都是用 img 来实现的。渐渐发现一个页面的请求资源中图片 img 占了大部分,所以为了优化有了
image sprite
就是所谓的雪碧图,就是将多个图片合成一个图片,然后利用 css 的 background-position 定位显示不同的 icon 图标。但这个也有一个很大的痛点,维护困难。每新增一个图标,都需要改动原始图片,还可能不小心出错影响到前面定位好的图片,而且一修改雪碧图,图片缓存就失效了,久而久之你不知道该怎么维护了。
font 库
后来渐渐地一个项目里几乎不会使用任何本地的图片了,而使用一些 font 库来实现页面图标。常见的如
Font Awesome
,使用起来也非常的方便,但它有一个致命的缺点就是找起来真的很不方便,每次找一个图标特别的费眼睛,还有就是它的定制性也非常的不友善,它的图标库一共有675个图标,说少也不少,但还是会常常出现找不到你所需要图标的情况。当然对于没有啥特别 ui 追求的初创公司来说还是能忍一忍的。但随着公司的壮大,来了越来越多对前端指手画脚的人,丧心病狂的设计师,他们会说不!这icon这么丑,这简直是在侮辱他们高级设计师的称号啊!不过好在这时候有了
iconfont
。
iconfont
一个阿里爸爸做的开源图库,人家还有专门的
github issue
(虽然我的一个 issue 半年多了也没回应/(ㄒoㄒ)/~~),但人家的图标数量还是很惊人的,不仅有几百个公司的开源图标库,还有各式各样的小图标,还支持自定义创建图标库,所以不管你是一家创业公司还是对设计很有要求的公司,它都能很好的帮助你解决管理图标的痛点。你想要的基本都有~
iconfont 三种使用姿势
unicode
最开始我们使用了
unicode
的格式,它主要的特点是
优势
兼容性最好,支持ie6+
支持按字体的方式去动态调整图标大小,颜色等等
劣势
使用方法:
第一步:引入自定义字体
font-face
@font-face {
font-family : "iconfont" ;
src : url('iconfont.eot') ;
src : url('iconfont.eot#iefix') format ( 'embedded-opentype' ) ,
url('iconfont.woff') format ( 'woff' ) ,
url('iconfont.ttf') format ( 'truetype' ) ,
url('iconfont.svg#iconfont') format ( 'svg' ) ;
}
第二步:定义使用iconfont的样式
.iconfont {
font-family : "iconfont" !important ;
font-size : 16 px;
font-style : normal;
-webkit-font-smoothing : antialiased;
-webkit-text-stroke-width : 0.2 px;
-moz-osx-font-smoothing : grayscale;
}
第三步:挑选相应图标并获取字体编码,应用于页面
< i class = " iconfont" > i
>
效果图:
其实它的原理也很简单,就是通过
@font-face
引入自定义字体(其实就是一个字体库),它里面规定了
这个对应的形状就长这企鹅样。其实类似于 '花裤衩',在不同字体设定下长得是不同的一样。
不过它的缺点也显而易见,
unicode
的书写不直观,语意不明确。光看
这个
unicode
你完全不知道它代表的是什么意思。这时候就有了
font-class
。
font-class
与unicode使用方式相比,具有如下特点:
使用方法:
第一步:拷贝项目下面生成的fontclass代码:
. . / font_8d5l8fzk5b87iudi. css
第二步:挑选相应图标并获取类名,应用于页面:
< i class = " iconfont icon-xxx" > i >
效果图:
它的主要原理其实是和
unicode
一样的,它只是多做了一步,将原先
这种写法换成了
.icon-QQ
,它在每个 class 的 before 属性中写了
unicode
,省去了人为写的麻烦。如
.icon-QQ:before { content: "\e604"; }
相对于
unicode
它的修改更加的方便与直观。但也有一个大坑,之前楼主一个项目中用到了两组
font-class
由于没有做好命名空间,所有的class都是放在
.iconfont
命名空间下的,一上线引发了各种雪崩问题,修改了半天,所以使用
font-class
一定要注意命名空间的问题。
symbol
随着万恶的某某浏览器逐渐淡出历史舞台,svg-icon 使用形式慢慢成为主流和推荐的方法。相关文章可以参考张鑫旭大大的文章
未来必热:SVG Sprite技术介绍
使用方法:
第一步:拷贝项目下面生成的symbol代码:
引入 . / iconfont. js
第二步:加入通用css代码(引入一次就行):
< style type = " text/css" >
.icon {
width : 1 em; height : 1 em;
vertical-align : -0.15 em;
fill : currentColor;
overflow : hidden;
}
style >
第三步:挑选相应图标并获取类名,应用于页面:
< svg class = " icon" aria-hidden = " true" >
< use xlink: href= " #icon-xxx" > use >
svg >
使用svg-icon的好处是我再也不用发送
woff|eot|ttf|
这些很多个字体库请求了,我所有的svg都可以内联在html内。
还有一个就是 svg 是一个真正的矢量,不管你再怎么的放缩它都不会失真模糊,而且svg可以控制的属性也更加的丰富,也能做出更加生动和复杂的图标。现在ui设计师平时都喜欢使用 sketch 来工作,只要轻松一键就能导出 svg 了,所以 svg 也更受设计师的青睐。
Inline SVG vs Icon Fonts
这篇文章详细的比较了
svg
和
icon-font
的优劣,大家可以去看看。
PS:这里其实还用到了
SVG Sprite
技术。简单的理解就是类 svg 的似雪碧图,它在一个 svg 之中运用 symbol 标示了一个一个的 svg 图标,这样一个页面中我们遇到同样的 svg 就不用重复再画一个了,直接使用
就能使用了,具体的细节可以看这篇文章开头的文章
未来必热:SVG Sprite技术介绍
,在之后的文章中也会手摸手叫你自己如何制作
SVG Sprite
。
创建 icon-component 组件
我们有了图标,接下来就是如何在自己的项目中优雅的使用它了。
之后的代码都是基于 vue 的实例(ps: react 也很简单,原理都是类似的)
//components/Icon-svg
< template>
< svg class = " svg-icon" aria-hidden = " true" >
< use :xlink:href = " iconName" > use >
svg >
template >
< script>
export default {
name: 'icon-svg' ,
props: {
iconClass: {
type: String,
required: true
}
} ,
computed: {
iconName ( ) {
return `#icon- ${ this . iconClass}
`
}
}
}
script >
< style>
.svg-icon {
width : 1 em;
height : 1 em;
vertical-align : -0.15 em;
fill : currentColor;
overflow : hidden;
}
style >
import IconSvg from '@/components/IconSvg'
Vue. component ( 'icon-svg' , IconSvg)
< icon- svg icon- class = "password" / >
就这样简单封装了一个
Icon-svg
组件 ,我们就可以简单优雅的在自己的vue项目之中使用图标了。
进一步改造
但作为一个有逼格的前端开发,怎能就此满足呢!目前还是有一个致命的缺点的,就是现在所有的
svg-sprite
都是通过 iconfont 的
iconfont.js
生成的。
你完全不知道哪个图标名对应什么图标,一脸尼克扬问号??? 每次增删改图标只能整体js文件一起替换。
其次它也做不到
按需加载
,不能根据我们使用了那些 svg 动态的生成
svg-sprite
。
自定义性差
,通常导出的svg包含大量的无用信息,例如编辑器源信息、注释等。通常包含其它一些不会影响渲染结果或可以移除的内容。
添加不友善
,如果我有一些自定义的svg图标,该如何和原有的
iconfont
整合到一起呢?目前只能将其也上传到
iconfont
和原有的图标放在一个项目库中,之后再重新下载,很繁琐。
使用 svg-sprite
接下来我们就要自己来制作
svg-sprite
了。这里要使用到
svg-sprite-loader
这个神器了, 它是一个 webpack loader ,可以将多个 svg 打包成
svg-sprite
。
我们来介绍如何在
vue-cli
的基础上进行改造,加入
svg-sprite-loader
。
我们发现
vue-cli
默认情况下会使用
url-loader
对svg进行处理,会将它放在
/img
目录下,所以这时候我们引入
svg-sprite-loader
会引发一些冲突。
//默认`vue-cli` 对svg做的处理,正则匹配后缀名为.svg的文件,匹配成功之后使用 url-loader 进行处理。
{
test: /\.(png|jpe?g|gif|svg) (\?.*) ?$/,
loader: 'url-loader',
options: {
limit: 10000 ,
name: utils.assetsPath('img/[ name]