Icon是web开发中很常见的元素。icon的采用很普遍,其易被识别的特征,可以用来吸引、警告用户,并且(如果运用恰当)能在很大程度上提高用户体验。

我们在web中运用icon的时候,选择其实极为有限。

  • Icon Spritesheet
  • Icon字体
  • 内联svg
  • svg图片元素

这些都是今天常用的方式,就好比SVG元素和icon字体。在这篇文章中,我们会深入研究web开发中每一种icon的方法,并且会研究哪一种方法的性能最优。

Icon Spritesheet

我们通过许多小的图片(icon图片文件)合并为一份大文件的方式创建icon spritesheet,会用到CSS background-image,background-size和background-position的方法从icon spritesheet中展示图片。

Spritesheet example

Spritesheet样例>

我们可以采用SVG spritesheet来确保在每种显示器上都可以正常展示(普通显示器和Retina显示器)并且可以结合PNG spritesheet作为旧版本浏览器的候选方案。我们可是使用JavaScript库比如Modernizr来侦测用户的浏览器是否能支持SVG,在不支持的情况下以PNG作为备选。

我们来创建一个可行的icon

1
2
<span aria-hidden="true" class="icon icon--email"></span>
<span class="hidden--visually">Send me an Email</span>

spritesheet CSS例子(可以复制或者手动键入)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.icon {   
background-image: url('../images/spritesheet.svg');
background-repeat: no-repeat;
display: inline-block;
width: 64px; height: 64px;
}
.no-svg .icon {
background-image: url('../images/spritesheet.png');
}
.icon--email {
width: 64px;
height: 64px;
background-position: 0px 0px;
}

如果你还在想CSS样式hidden–visually是如何隐藏内容的,我在其他一篇我之前的文章中介绍过。

我们一起来评价使用icon spritesheet的优点和缺点吧。

优点

  • 增加icon的过程可以很容易被自动化
  • 图片优化技术能给压缩spritesheet文件的体积
  • 能在所有显示器中正常显示(当SVG spritesheet可用的时候)
  • 非常不错的浏览器支持(当PNG做备用方案时)
  • 减少请求的次数(当HTTP/2不被使用的时候)

缺点

  • 在盒状模型外不可使用。只有在手动添加额外的HTML元素时可用。
  • 很糟糕的样式
  • 所有的icon的变化都需要作为单独的元素添加到spritesheet中。
  • 在多人协作中同时添加新的icon时容易出现冲突。
  • 在使用HTTP/2的时候没有任何性能优势。

工具

Icon字体

我们可以制作包含着所需icon的字体文件来替单一的将icon合并成图片文件的方法。浏览器会将icon的字体文件当作样式更加友好文字样式来处理。

有许多制作和管理icon字体、CSS的工具,生成的CSS文件会如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* Define font icon font family */ 

@font-face {
font-family: 'myIconFont';
src: url('/path/to/myIconFont.ttf?r9c57c') format('truetype'),
url('/path/to/myIconFont.woff?r9c57c') format('woff'),
url('/path/to/myIconFont.svg?r9c57c#myIconFont') format('svg');
font-weight: normal;
font-style: normal;
}

/* Define icon class that sets font family and shared font styles */

.icon {
font-family: 'myIconFont';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

/* Define individual icon class that inserts the icon as a character in pseudo-element */

.icon--email::before {
content: '\e900';
}

我们来实现一个icon效果

1
2
<span aria-hidden="true" class="icon icon--email"></span>
<span class="hidden--visually">Send me an Email</span>

下面是使用icon字体的优点和缺点。

优点

  • 更好的优化效果
  • 可以在许多的工具中编辑和生成
  • 非常友好的浏览器支持
  • 易于使用

缺点

  • 字体的抗锯齿效果可能会对icon的渲染产生一定的影响
  • 在字体文件下载和加载的时候,页面上可能什么都不会显示
  • 在用户使用额外字体或者样式重写的时候很容易被覆盖掉
  • 在盒状模型外不可使用。只有在手动添加时可用

工具

  • icomoon - 管理和生成icon字体文件和CSS文件
  • fontello - 管理和生成icon字体文件和CSS文件
  • icon-font-generator - 将SVG文件转化为icon字体文件的NPM插件

内联SVG icon

相比起引入某些文件(spritesheet或者icon字体)的方法,我们可以直接将SVG数据嵌入到HTML文档中,浏览器会解析和展示SVG元素,由于我们可以单独设置每一个元素的样式,所以内联SVG元素是高度可定制的。

我们来看一个使用内联式SVG的代码:

1
2
3
4
5
<svg labelledby="titleId descId" role="group">     
<title id="titleId">Example title</title>
<desc id="descId">Long description explaining this example</desc>
<!-- SVG icon code -->
</svg>

我们使用标签为“titleId descId”作为SVG元素的标题和说明,会让元素对于辅助设备来说更加友好。将role设置为”presentation”也非常重要,因为这样会更加突出SVG的图形部分,并且被辅助设备忽略。

我们一起来评价使用内联SVG的优点和缺点吧。

优点

  • 与HTML同步加载,不需要额外的载入时间
  • 没有额外的HTTP请求
  • 具有良好可读性,无需额外HTML元素支持
  • 在不同显示器的解析度中效果都不错
  • 就样式选择来说是最优的(甚至可以为<svg>元素设置样式)

缺点

  • 复杂的HTML文档标记(取决于使用的框架)
  • 难以管理和维护(同样也取决于使用的框架)
  • icon不会被浏览器缓存
  • 许多旧版本(或者很少使用)的浏览器不支持内联SVG

许多框架让icon的管理和维护变得容易。比如说,Webpack会生产版本中将所有在”/path/to/myIcon.svg”引入的文件转变为内联SVG。对于开发人员来说,更加便于管理项目。

svg图片元素

我们可以用<img>元素来引入单独的SVG文件,而不是一个<svg>标签。这可以让文件更小而且更加简便而且更加易于维护。

我们用这种方法写一个icon

1
<img src="email.svg" alt="Send me an email">

我们可以用srcset标记来设置旧版本浏览器的备用方案。

1
<img src="email.png" alt="Send me an email" srcset="email.png">

支持srcset标记的浏览器同时也会支持SVG元素,而且能自动载入SVG图片。对于不支持此标记的浏览器会自动加载PNG备用方案。

来看一下使用内联SVG图片元素的优点和缺点。

优点

  • 标签简单
  • 内建简单且可读性高的alt标记的
  • 不错的浏览器兼容(如果PNG备用方案可用)
  • 可以压缩的图片文件
  • 图片文件可以被浏览器缓存(仅需一次下载)

缺点

  • 很糟糕的样式
  • 不同的icon(比如不同颜色)需要载入不同的文件
  • 每一个icon需要许多次请求(在没有缓存的情况下)