专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
OSC开源社区  ·  Bun ... ·  昨天  
OSC开源社区  ·  RAG市场的2024:随需而变,从狂热到理性 ·  昨天  
码农翻身  ·  漫画 | 为什么大家都愿意进入外企? ·  2 天前  
程序员的那些事  ·  印度把 DeepSeek ... ·  3 天前  
51好读  ›  专栏  ›  SegmentFault思否

手摸手,带你优雅的使用 icon

SegmentFault思否  · 公众号  · 程序员  · 2017-12-04 08:00

正文

前言

本篇文章其实陆陆续续写了快半年,主体部分写好了很久了,但由于种种原因一直没有发布。 首先来说说写这篇文章的主要初衷是:在做前端后台项目的时候经常会用到很多 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-size、line-height、word-spacing等CSS属性的影响,而且这种影响调整起来较为困难

使用方法: 第一步:引入自定义字体 `font-face

  1. @font-face {

  2.   font-family: "iconfont";

  3.   src: url('iconfont.eot'); /* IE9*/

  4.   src: url('iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */

  5.   url('iconfont.woff') format('woff'), /* chrome, firefox */

  6.   url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/

  7.   url('iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */

  8. }

第二步:定义使用iconfont的样式

  1. .iconfont {

  2.  font-family: "iconfont" !important;

  3.  font-size:16px;

  4.  font-style:normal;

  5.  -webkit-font-smoothing: antialiased;

  6.  -webkit-text-stroke-width: 0.2px;

  7.  -moz-osx-font-smoothing: grayscale;

  8. }

第三步:挑选相应图标并获取字体编码,应用于页面

  1. class="iconfont">

效果图:

其实它的原理也很简单,就是通过 @font-face 引入自定义字体(其实就是一个字体库),它里面规定了 这个对应的形状就长这企鹅样。其实类似于 '花裤衩',在不同字体设定下长得是不同的一样。

不过它的缺点也显而易见, unicode 的书写不直观,语意不明确。光看 这个 unicode 你完全不知道它代表的是什么意思。这时候就有了 font-class

font-class

与unicode使用方式相比,具有如下特点:

  • 兼容性良好,支持ie8+

  • 相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。

使用方法: 第一步:拷贝项目下面生成的fontclass代码:

  1. ../font_8d5l8fzk5b87iudi.css

第二步:挑选相应图标并获取类名,应用于页面:

  1. class="iconfont icon-xxx">

效果图:

它的主要原理其实是和 unicode 一样的,它只是多做了一步,将原先 这种写法换成了 .icon-QQ ,它在每个 class 的 before 属性中写了 unicode ,省去了人为写的麻烦。如 .icon-QQ:before{content:"\e604";}

相对于 unicode 它的修改更加的方便与直观。但也有一个大坑,之前楼主一个项目中用到了两组 font-class 由于没有做好命名空间,所有的class都是放在 .iconfont 命名空间下的,一上线引发了各种雪崩问题,修改了半天,所以使用 font-class 一定要注意命名空间的问题。

symbol

随着万恶的某某浏览器逐渐淡出历史舞台,svg-icon 使用形式慢慢成为主流和推荐的方法。相关文章可以参考张鑫旭大大的文章未来必热:SVG Sprite技术介绍

  • 支持多色图标了,不再受单色限制。

  • 支持像字体那样通过font-size,color来调整样式。

  • 支持 ie9+

  • 可利用CSS实现动画。

  • 减少HTTP请求。

  • 矢量,缩放不失真

  • 可以很精细的控制SVG图标的每一部分

使用方法: 第一步:拷贝项目下面生成的symbol代码:

  1. 引入  ./iconfont.js

第二步:加入通用css代码(引入一次就行):

第三步:挑选相应图标并获取类名,应用于页面:

  1. class="icon" aria-hidden="true">

  2.     xlink:href="#icon-xxx" >

使用svg-icon的好处是我再也不用发送 woff|eot|ttf| 这些很多个字体库请求了,我所有的svg都可以内联在html内。

还有一个就是 svg 是一个真正的矢量,不管你再怎么的放缩它都不会失真模糊,而且svg可以控制的属性也更加的丰富,也能做出更加生动和复杂的图标。现在ui设计师平时都喜欢使用 sketch 来工作,只要轻松一键就能导出 svg 了,所以 svg 也更受设计师的青睐。Inline SVG vs Icon Fonts 这篇文章详细的比较了 svg icon-font 的优劣,大家可以去看看。PS:这里其实还用到了 SVGSprite 技术。简单的理解就是类 svg 的似雪碧图,它在一个 svg 之中运用 symbol 标示了一个一个的 svg 图标,这样一个页面中我们遇到同样的 svg 就不用重复再画一个了,直接使用 就能使用了,具体的细节可以看这篇文章开头的文章 未来必热:SVG Sprite技术介绍,在之后的文章中也会手摸手叫你自己如何制作 SVGSprite

创建 icon-component 组件

我们有了图标,接下来就是如何在自己的项目中优雅的使用它了。 之后的代码都是基于 vue 的实例(ps: react 也很简单,原理都是类似的)

  1. //components/Icon-svg

  2.   class="svg-icon" aria-hidden="true">

  3.     :xlink:href="iconName">

  4.  

  5. true

  6.    }

  7.  },

  8.  computed: {

  9.    iconName() {

  10.      return `#icon-${this.iconClass}`

  11.    }

  12.  }

  13. }