随着时代的变迁与技术的不断的更新,在当今这个时代,Web中的图标(Icons)不再仅仅是局限于<img>
。除了<img>
直接调用Icons文件之外,还有Sprites(俗称雪碧图)、Icon Font(字体图标)、SVG Icon等等。今天我们就来一起探讨一下这些方法在Web中实现Icon的利弊。
思考变革
设计师不管分辨率(Resolution independent)和设备平台,其追求像素完美(Pixel Perfection)、体验一致性;而前端工程师们更为关心的是页面的可访问性(Accessability)、性能以及重构的灵活性,可复用性,可维护性等等。
而当下这个互联网时代,设备多样化,显示分辨率层出不穷,对于Web前端工程师来说可是灾难性,而且碰到的难题也是越来越多:
- 需要为高PPI(Retina显屏)显示设备准备
1.5x
、2x
和3x
的图标素材 - 需要针对不同分辨率来调整优化排版
- 需要考虑不同平台下图片加载的性能问题
- 需要考虑可访问性,可维护性问题
- 要考虑的还有很多很多.........
前途是光明的,道路是曲折的。前端工程师一直以来就是见招拆招,从未停止过自己向前的步伐。不信我们一起来看。
原始的<img>
<img>
标签,大家都知道是用来给Web页面添加图片的。而图标(Icons)其实也是属于图片,因而在页面中可以直接使用<img>
标签来加载图标。并且可以加载任何适用于Web页面的图标格式,比如:.jpg
(或.jpeg
)、.png
、.gif
。对于今天的Web,除了这几种图片格式之外,还可以直接引用.webp
和.svg
图像(图标)。
优势
- 更换简单方便,只需要修改图标路径或覆盖图标文件名
- 图标大小易于掌握
看上去这都不是什么优势,我也只能为其想到这两条了。
劣势
- 增加HTTP请求数,如果页面使用的图标过多,直接拉高了HTTP的请求数,也就直接影响页面的加载性能
- 不易适配各种终端和分辨率,特别是高PPI的显示设备,有可能会造成图标模糊(除非是通过
img
加载矢量图标.svg
,或者一开始就加载适合高PPI的图标) - 不易修改图标的样式,比如颜色,阴影等
- 不易维护
Sprites 图标(雪碧图)
虽然img
可以帮助前端工程师往Web页面中添加需要的图标,但其不足之处也是众所周知的。由于img
的局限性与不足,2004年3月@Dave Shea提出了一种全新的技术CSS Sprites(在国内常常将这种技术称为CSS雪碧,又称CSS精灵)。
CSS Sprites出现之后,很多互联网团队都在使用这种技术,比如:
当然,国内使用CSS Sprites也不少:
诸如此类的还很有很多。
在此对于CSS Sprites的技术就不做过多的阐述,如果您想了解这方面的相关知识,可以阅读下面的文章科普:
- CSS Sprites: Image Slicing’s Kiss of Death
- The Mystery Of CSS Sprites: Techniques, Tools And Tutorials
- CSS Sprites: Useful Technique, or Potential Nuisance?
Sprites分类
早期CSS Sprites使用的都是位图,而且为了适合Web页面使用环境,采用的都是.png
文件格式,但在现在只使用位图,会受到很多的限制,比如在Retina屏下,位图会模糊。也就是说,为了适配各种终端设备分辨,CSS Sprites不在局限于位图,也可以将SVG这样的矢量图集合在一起。其和位图最大的不同之处可以根据设备分辨率,调整Sprites的尺寸,从而不影响图标在设备的呈现质量。
相对而言,SVG更适合当前的Web页面,当然,这种技术也受到一定的局限性,比如说修改ICON图标颜色之类,就必须去修改.svg
文件,这对于前端人员来说是无法接受。有关于SVG Sprites相关的介绍,可以阅读下面相关文章:
优势
- 减少HTTP请求数
- 可以是任意图形,也可以是任意色彩
- 兼容性极好(对于位图的Sprites兼容性都非常的好,但对于SVG的Sprites,还是受到浏览器的限制,最起码要支持SVG的浏览器才能得到支持)
劣势
- 增加开发时间,需要人肉或通过相关工具,将零散的图形合并到一起,而不同的合并方式,图形的色彩对Web的性能有直接的影响;
- 增加维护成本,要增加新的图标合成进来,是件较难的事情,甚至直接会影响到前面又定位好的图片。目前为止,使用自动编译工具,相对比人肉处理要理想一些;
- 图片尺寸固定,在位图的Sprites中无法通过CSS来修改图标的大小,但在SVG的Sprites中可以配合CSS的
background-size
调整图标的大小;
字体图标(Icon Font)
虽然CSS Sprites有其足够的优势,而且众多开发者都在使用这种技术,但是到了今天,不得不对CSS Sprites说再见(其实是跟位图的图标说再见)。
随着Retina屏幕的出现,大家都发现自己在Web中使用的图标变得模糊不清,直接拉低了自己产品的品质。对于Web前端人员也必须面对考虑各种 高清屏幕的显示效果。由此也造成同样的前端在代码实现的时候需要根据屏幕的不同来输出不同分辨率的图片。不管你采用的是何种手段:
- 通过
image-set
实现Retina屏幕下的图像显示 - 通过媒体查询,在不同的屏幕下调用不同的图像
- 使用
img
的srcset
属性调用不同的图像 - 使用
<picture>
标签元素根据不同的屏幕调用不同的图像
不管使用哪种方法,都不是一件易事,比如使用image-set
和媒体查询,只适合背景图像;而对于srcset
和picture
方法仅适合Web引入图像的情景。而且这些方法直到目前为止在浏览器上都受到了很多的限制。
为了解决屏幕分辨率对图标影响的问题,字体图标(Icon Font)就顺势而生了。字体图标是一种全新的设计方式,更为重要的是相比位图而言,使用字体图标可以不受限于屏幕分辨率,冲着这一点就具有非常强的优 势,而且字体图标还具有一个优势是,只要适合字体相关的CSS属性都适合字体图标,比如说:
- 使用
font-size
修改图标大小 - 使用
color
修改图标颜色 - 使用
text-shadow
给图标增加阴影 - ....
基于这些原因,现在Web开发中,使用字体来制作图标的应用也越来越多。
优势
- 减少了HTTP的请求
- 很容易任意地缩放
- 很容易地改变颜色
- 很容易地产生阴影
- 可以拥有透明效果
- 浏览器兼容性较好
- 可以到很CSS很好支持
- 可以快速转化形态
- 可以做出跟位图一样可以做的事情
- 本身体积更小
劣势
- 它们只能被渲染成单色或CSS3的渐变色
- 使用限制性很大,除非你想花时间去创作你自己的字体图标
- 创作字体图标很耗时间
- 可访问性差
- 字体文件体积过大,直接影响页面加载性能,特别是加载一个包含数百图标的Fonts,却只使用其中几个图标
- 在不同的设备浏览器字体的渲染会略有差别,在不同的浏览器或系统中对文字的渲染不同,其显示的位置和大小可能会受到
font-size
、line-height
、word-spacing
等CSS属性的影响,而且这种影响调整起来较为困难 - 为了实现最大程度的浏览器支持,可能要提供至少四种不同类型的字体文件。包括
.ttf
、.woff
、.eot
和.svg
格式字体 - 不兼容旧的手机浏览器:Opera mini,Android 2.1,Windows Phone 7.5-7.8
- 在手机上可能与系统字体冲突
SVG图标
为了适配各种分辨率,让图标显示更完美,除了字体图标之外,还可以使用SVG图标。SVG图标是一种矢量图标。其实回过头来看,字体图标其实也是使用SVG封装过的。
为什么要使用SVG图标
SVG图标实际上是一个服务于浏览器的XML文件,而不是一个字体或像素的位图。它是由浏览器直接渲染XML,在任何大小之下都会保持图像清晰。而 且文件中的XML还提供了很多机会,可以直接在代码中使用动画或者修改颜色,描边等。不需要借助任何图形编辑软件都可以轻松的自定义图像。除此之 外,SVG图像也有过字体图标的一个主要优势:拥有多个彩色图像的能力。
优势
- SVG图标是矢量图形文件,可以随意修改大小,而且不会影响图标质量
- 可以使用CSS样式来自定义图标颜色,比如颜色、尺寸等效果
- 所有SVG图标可以全部放在一个SVG的文件中(SVG Sprites),节省HTTP的请求
- 使用SMIL、CSS或者JavaScript可以制作动画效果
- 可以使用gzip的方式把文件压缩到很小
- 可以很精细的控制SVG图标的每一部分
劣势
- 浏览器兼容性较差
- 需要学习SVG相关知识
- 需要了解使用制作软件绘制SVG图形或专业的SVG图形编辑软件
为什么要使用SVG图标替代字体图标
为了让图标能更好的适配各种屏幕分辨率,大家首先的就是字体图标和SVG图标,那么这里为何又要谈:为什么要使用SVG图标替代字体图标。@Chris Coyier的《Inline SVG vs Icon Fonts》(中文译文可以点击这里阅读)和@Ian Feather的《Ten reasons we switched from an icon font to SVG》(中文译文可以点击这里阅读)。
字体图标 vs SVG图标
字体图标 | SVG图标 | |
---|---|---|
图标是矢量 | 浏览器会以字体解析它,所以浏览器会以文字的方式来对图标做抗锯齿处理,这可以导致字体图标没有期待中的那么锐利 | SVG是XML文件,浏览器直接解析XML文件,直接就是矢量图形,图标锐利,体积也小 |
可控制性 | 可以通过font-size、color、text-shadow等CSS来控制图标 | 除了字体图标一样的CSS控制方法之外,还可以单独控制一个复合SVG图标中的某一部分,也可以给图标描边 |
控制图标位置 | 图标位置会受到line-height、vertical-align、letter-spacing等属性影响 | SVG图标的大小就是很精确的SVG图形的大小 |
图标加载 | 跨域时没有合理的CORS头部、字体文件未加载、@font-face在Chrome中的bug和不支持@font-face的浏览器等,这些原因都会造成字体图标渲染失败 | SVG图标就是文档本身,只要支持SVG的浏览器,都能正常的渲染 |
语义化,易访问性 | 为了更好的显示图标,通常使用伪元素或伪类来做,这样做语义化较差 | SVG图标就是一个小图片。SVG的语义就是”我是一张图片“,感觉可能更好 |
易用性 | 使用一个已造好的字体图标集从来都不有效,因为有太多的图标未使用。而创建一个你自己的字体图标集也不是轻松的事情,需要懂得相关的编辑工具或应用软件 | SVG图标会简单一些,因为你可以自己手动地操作,如果需要的话,你可以使用相关的编辑工具 |
浏览器支持度 | 得到非常好的支持性,可以一直支持到IE6,在Opera mini,Android 2.1,Windows Phone 7.5-7.8没到支持 | 浏览器支持性一般,IE8和Android 2.1以及其以下浏览器不支持。不支持可以采用降级处理,但不并完美 |
DataURI
DataURI是利用Base64编码规范将图片转换成文本字符,不仅是图片,还可以编码JS、CSS、HTML等文件。通过将图标文件编码成文本字符,从而可以直接写在HTML/CSS文件里面,不会增加任何多余的请求。
但是DataURI的劣势也是很明显的,每次都需要解码从而阻塞了CSS渲染,可以通过分离出一个专用的CSS文件,不过那就需要增加一个请求,那 样与CSS Sprites、Icon Font和SVG相比没有了任何优势,也因此,在实践中不推荐这种方法。需要注意的是通过缓存CSS可以来达到缓存的目的。
优势:
- 不增加请求数
劣势:
- 通常比图片要大不到10%
- 每次加载页面都需要解码
- 不支持IE6/7,IE8最大支持32KB
- 难于维护
性能对比
不管使用哪种方案来制作Web页面的图标,大家都会比较关心其对页面的性能有多大的影响。在这里提供一个测试用例,在这些用例中,页面加载了282
个32 x 32
的图标。
这些图标直接通过IcoMoon APP获取。并且分别采用了img
加载.png
、CSS Sprites(png和svg的Sprites)、字体图标和SVG图标的方式写的用例:
具体代码就不做演示,接下来通过在线性能测试工具WebPageTest(除了这个在线测试工具之外,还可以点击这里获取其他的在线测试工具)来做一个简单的测试。当然这样的测试可能不会非常的准确,但或多或少能从相关的数据上向大家形象的展示不同的方案对页面性能的影响会有多大。
特别声明:以下提供的测试数据受到网络直接影响,仅提供做为示例参考。
PNG/SVG文件
页面使用<img>
加载了282
个.png
或.svg
图标。每个图标的大小是32px x 32px
。
PNG Sprites
将282
个.png
图标集成在一个Sprites文件中,Sprites图片文件大小是108kb
。
SVG Sprites
将282
个.svg
图标集成在一个Sprites文件中,Sprites图片文件大小是180kb
。
SVG
在页面中直接使用SVG源码制作的图标。
Icon Font
使用Font制作的图标。
以上图表中的数据仅做参考,因为在线测试,网速之类直接影响到测试结果。熟悉性能测试的同学,可以直接在本地测试用例,拿到更具有价值的参考数据。也希望同学能将这方面的结果在评论中与我们一起分享。
如何选择
前面介绍了Web中制作图标的几种常见方案,每种方案都有其自己的利弊。那在实际中要如何选择呢?这需要根据自身所在的环境来做选择:
- 如果你需要信息更丰富的图片,不仅仅是图标时,可以考虑使用
<img>
- 使用的不是展示类图形,而是装饰性的图形(包括图标),而且这部分图形一般不轻意改变,可以考虑使用PNG Sprites
- 如果你的图标之类需要更好的适配于高分辨率设备环境之下,可以考虑使用SVG Sprites
- 如果仅仅是要使用Icon这些小图标,并且对Icon做一些个性化样式,可以考虑使用Icon Font
- 如果你需要图标更具扩展性,又不希望加载额外的图标,可以考虑在页面中直接使用SVG代码绘制的矢量图
当然,在实际开发中,可能一种方案无法达到你所需的需求,你也可以考虑多种方案结合在一起使用。
总结
全文主要介绍了Web中图标的几种方案之间的利与弊。相对而言,如果不需要考虑一些低版本用户,就当前这个互联网时代,面对众多终端,较为适合的方案还是使用SVG。不管是通过img
直接调用.svg
的 文件还是使用SVG的Sprites,或者直接在页面中使用SVG(直接代码),都具有较大的优势。不用担心,使用的图标在不同的终端(特别是在 Retina屏)会模糊不清。而且SVG还有一个较大的优势,你可以直接在源码中对SVG做修改,特别是可以分别控制图标的不同部分,加入动画等。
当然,你或许会有众多的顾虑,不懂SVG的怎么破,就算不懂SVG,你也可以借助SVG的图形编辑软件或者工具,来协助你。除此之外,除了这些方式 在Web中嵌入图标之外,对于一些简单的小图标,可以考虑直接使用CSS代码来编写,这种方式可能较为费时费力,但其具有的优势,我想大家都懂的。