Font Awesome是Dave Gandy通过字体制作的几百个icons图标。在前端界享有盛名。使用@font-face制作的图标可以随意的放大,并通过CSS中字体相关的CSS对图标进行美化,比如说可以改变图标颜色、大小和增加阴影等,但他也存在一定的弊端。
很多时候,在项目中为了调用整套图标中的某几个时,为了使用Font Awesome制作的图标,我们不得不被迫加载制作icon的所有样式和文件。比如:
.fa-glass:before {
content: "\f000";
}
.fa-music:before {
content: "\f001";
}
.fa-search:before {
content: "\f002";
}
.fa-envelope-o:before {
content: "\f003";
}
.fa-heart:before {
content: "\f004";
}
.fa-star:before {
content: "\f005";
}
...
如此一来,造成文件臃肿,而且有很多冗余没用的代码。
这个时候,我们都在思考,有没有办法能帮助我们,使用Font Awesome图标能按我们所需调用需要图标的样式。换句话说,如果我们需要一个图标,就使用这个图标对应的样式,如果我们需要某几个图标,我们就使用这几个图标对应的样式。看似蛮有意思,那么我们今天,就一起来探讨这个问题。
带着这样的问题,我在想,是否可以使用CSS预处理器语言中的Sass来进行处理。了解Sass的同学都知道,Sass可以进行一些预编码处理,比如说定义mixins、%placeholder等,当需要使用的时候,通过@include和@extend来调用。甚至还可以像其他程序一样,定义函数功能,实现一些自定的功能。那么我们今天就借助Sass的这些特性,来做进一步的思考,是否能通过Sass来帮助我们实现我们前面所说的需求。
在Font Awesome字体图库中,每个图标都有一个对应的编码,比如说glass=>"\f000"
,music=>"\f001"
。整个图库我们有近三百个不同的图标,也就是说我们有三百多个这样的实体编码。那么针对这种现像,我们是否可以考虑像其他的程序语言一样,给他们定义一个数组,并将此数组赋值给一个变量。按照这样的思路来说,在Sass中正好具有这样的特性,我们可以将所有图标对应的编码以数组的形式赋值给一个变量。
有了数组就解决我们一大问题,为什么这么说呢?打个比方,我们需要其中的某个图标,我们是否需要一个类似遍历数组的函数,从整个列表中找到需要的东西。也就是说,我们需要在Sass中定义一个遍历数组的函数。
有了变量,也有了遍历功能,能帮助我们找到需要的图标,但我们还需要一些默认的样式功能,比如说,图标怎么调用,这个时候我们就需要通过Sass的mixin来制作,便于每次的调用。
数组、函数和功能都具有了,这个时候我们回到CSS面对的问题中。前面说过,在CSS中使用Font Awesome图库,不管我们需要使用的图标有多少,我们都必须全部加载。而我们真正需要的是要有一个开关——按需开启。也就是说,如果我只需要某几个图标,我能通过一定的方式只开启这几个对应的图标,调出他们对应的样式。如果我们需要所有的图标显示,我也有一个功能开关,可以通过某个功能,一下全部开启。
如此一来,我们的思路就很清楚了,我们使用Sass制作灵活开启图标,需要以下几个东东:
扯了一大通,大家可能想知道的是如何用Sass实现前面说的这一切。那我们现在就开始。
为了更好的说明整个实现过程,我们先创建本地创建一个项目,并把制作Font Awesome图标所需要的字体文件引入到项目中。而其中我们同时制作了一个文件夹"sass"来放置.scss
文件,并且创建一个文件夹"css",用来放置Sass编译出来的.css
文件。整个项目的结构如下所示:
+font-awesome
|-+--fonts
|-|----fontawesome-webfont.eot
|-|----fontawesome-webfont.svg
|-|----fontawesome-webfont.ttf
|-|----fontawesome-webfont.woff
|-+--stylesheets
|-|--+--sass
|-|--+--css
在Font Awesome的CSS样式当中,我们能看到一大堆类似于下面的代码:
...
.fa-film:before {
content: "\f008";
}
.fa-th-large:before {
content: "\f009";
}
...
而当中每个"\f008"
这样的编码就是对应的一个图标,而在Sass中,我们也需要这样的编码,不过不同的是,我们将其以数组的方式定义的。为了能更好的组织这些编码和其他相应的变量,特些在sass目录中创建了一个名叫_variables.scss
的文件,并且在这个文件中放置如下所示的代码:
@charset "UTF-8";
//Variables
$fa-css-prefix: icon- !default;
$fa-family-name: "FontAwesome" !default;
$file-path: "../../fonts/fontawesome-webfont" !default;
$icons:
glass "\f000",
music "\f001",
search "\f002",
envelope-o "\f003",
heart "\f004",
star "\f005",
star-o "\f006",
user "\f007",
film "\f008",
th-large "\f009",
th "\f00a",
th-list "\f00b",
check "\f00c",
times "\f00d",
search-plus "\f00e",
search-minus "\f010",
power-off "\f011",
signal "\f012",
cog "\f013",
trash-o "\f014",
home "\f015",
file-o "\f016",
clock-o "\f017",
road "\f018",
download "\f019",
arrow-circle-o-down "\f01a",
arrow-circle-o-up "\f01b",
inbox "\f01c",
play-circle-o "\f01d",
repeat "\f01e",
refresh "\f021",
list-alt "\f022",
lock "\f023",
flag "\f024",
headphones "\f025",
volume-off "\f026",
volume-down "\f027",
volume-up "\f028",
qrcode "\f029",
barcode "\f02a",
tag "\f02b",
tags "\f02c",
book "\f02d",
bookmark "\f02e",
print "\f02f",
camera "\f030",
font "\f031",
bold "\f032",
italic "\f033",
text-height "\f034",
text-width "\f035",
align-left "\f036",
align-center "\f037",
align-right "\f038",
align-justify "\f039",
list "\f03a",
outdent "\f03b",
indent "\f03c",
video-camera "\f03d",
picture-o "\f03e",
pencil "\f040",
map-marker "\f041",
adjust "\f042",
tint "\f043",
pencil-square-o "\f044",
share-square-o "\f045",
check-square-o "\f046",
arrows "\f047",
step-backward "\f048",
fast-backward "\f049",
backward "\f04a",
play "\f04b",
pause "\f04c",
stop "\f04d",
forward "\f04e",
fast-forward "\f050",
step-forward "\f051",
eject "\f052",
chevron-left "\f053",
chevron-right "\f054",
plus-circle "\f055",
minus-circle "\f056",
times-circle "\f057",
check-circle "\f058",
question-circle "\f059",
info-circle "\f05a",
crosshairs "\f05b",
times-circle-o "\f05c",
check-circle-o "\f05d",
ban "\f05e",
arrow-left "\f060",
arrow-right "\f061",
arrow-up "\f062",
arrow-down "\f063",
share "\f064",
expand "\f065",
compress "\f066",
plus "\f067",
minus "\f068",
asterisk "\f069",
exclamation-circle "\f06a",
gift "\f06b",
leaf "\f06c",
fire "\f06d",
eye "\f06e",
eye-slash "\f070",
exclamation-triangle "\f071",
plane "\f072",
calendar "\f073",
random "\f074",
comment "\f075",
magnet "\f076",
chevron-up "\f077",
chevron-down "\f078",
retweet "\f079",
shopping-cart "\f07a",
folder "\f07b",
folder-open "\f07c",
arrows-v "\f07d",
arrows-h "\f07e",
bar-chart-o "\f080",
twitter-square "\f081",
facebook-square "\f082",
camera-retro "\f083",
key "\f084",
cogs "\f085",
comments "\f086",
thumbs-o-up "\f087",
thumbs-o-down "\f088",
star-half "\f089",
heart-o "\f08a",
sign-out "\f08b",
linkedin-square "\f08c",
thumb-tack "\f08d",
external-link "\f08e",
sign-in "\f090",
trophy "\f091",
github-square "\f092",
upload "\f093",
lemon-o "\f094",
phone "\f095",
square-o "\f096",
bookmark-o "\f097",
phone-square "\f098",
twitter "\f099",
facebook "\f09a",
github "\f09b",
unlock "\f09c",
credit-card "\f09d",
rss "\f09e",
hdd-o "\f0a0",
bullhorn "\f0a1",
bell "\f0f3",
certificate "\f0a3",
hand-o-right "\f0a4",
hand-o-left "\f0a5",
hand-o-up "\f0a6",
hand-o-down "\f0a7",
arrow-circle-left "\f0a8",
arrow-circle-right "\f0a9",
arrow-circle-up "\f0aa",
arrow-circle-down "\f0ab",
globe "\f0ac",
wrench "\f0ad",
tasks "\f0ae",
filter "\f0b0",
briefcase "\f0b1",
arrows-alt "\f0b2",
users "\f0c0",
link "\f0c1",
cloud "\f0c2",
flask "\f0c3",
scissors "\f0c4",
files-o "\f0c5",
paperclip "\f0c6",
floppy-o "\f0c7",
square "\f0c8",
bars "\f0c9",
list-ul "\f0ca",
list-ol "\f0cb",
strikethrough "\f0cc",
underline "\f0cd",
table "\f0ce",
magic "\f0d0",
truck "\f0d1",
pinterest "\f0d2",
pinterest-square "\f0d3",
google-plus-square "\f0d4",
google-plus "\f0d5",
money "\f0d6",
caret-down "\f0d7",
caret-up "\f0d8",
caret-left "\f0d9",
caret-right "\f0da",
columns "\f0db",
sort "\f0dc",
sort-down "\f0dc",
sort-asc "\f0dd",
sort-desc "\f0de",
envelope "\f0e0",
linkedin "\f0e1",
undo "\f0e2",
gavel "\f0e3",
tachometer "\f0e4",
dashboard "\f0e4",
comment-o "\f0e5",
comments-o "\f0e6",
bolt "\f0e7",
sitemap "\f0e8",
umbrella "\f0e9",
clipboard "\f0ea",
lightbulb-o "\f0eb",
exchange "\f0ec",
cloud-download "\f0ed",
cloud-upload "\f0ee",
user-md "\f0f0",
stethoscope "\f0f1",
suitcase "\f0f2",
bell-o "\f0a2",
coffee "\f0f4",
cutlery "\f0f5",
file-text-o "\f0f6",
building-o "\f0f7",
hospital-o "\f0f8",
ambulance "\f0f9",
medkit "\f0fa",
fighter-jet "\f0fb",
beer "\f0fc",
h-square "\f0fd",
plus-square "\f0fe",
angle-double-left "\f100",
angle-double-right "\f101",
angle-double-up "\f102",
angle-double-down "\f103",
angle-left "\f104",
angle-right "\f105",
angle-up "\f106",
angle-down "\f107",
desktop "\f108",
laptop "\f109",
tablet "\f10a",
mobile "\f10b",
mobile-phone "\f10b",
circle-o "\f10c",
quote-left "\f10d",
quote-right "\f10e",
spinner "\f110",
circle "\f111",
reply "\f112",
github-alt "\f113",
folder-o "\f114",
folder-open-o "\f115",
smile-o "\f118",
frown-o "\f119",
meh-o "\f11a",
gamepad "\f11b",
keyboard-o "\f11c",
flag-o "\f11d",
flag-checkered "\f11e",
terminal "\f120",
code "\f121",
reply-all "\f122",
mail-reply-all "\f122",
star-half-o "\f123",
location-arrow "\f124",
crop "\f125",
code-fork "\f126",
chain-broken "\f127",
question "\f128",
info "\f129",
exclamation "\f12a",
superscript "\f12b",
subscript "\f12c",
eraser "\f12d",
puzzle-piece "\f12e",
microphone "\f130",
microphone-slash "\f131",
shield "\f132",
calendar-o "\f133",
fire-extinguisher "\f134",
rocket "\f135",
maxcdn "\f136",
chevron-circle-left "\f137",
chevron-circle-right "\f138",
chevron-circle-up "\f139",
chevron-circle-down "\f13a",
html5 "\f13b",
css3 "\f13c",
anchor "\f13d",
unlock-alt "\f13e",
bullseye "\f140",
ellipsis-h "\f141",
ellipsis-v "\f142",
rss-square "\f143",
play-circle "\f144",
ticket "\f145",
minus-square "\f146",
minus-square-o "\f147",
level-up "\f148",
level-down "\f149",
check-square "\f14a",
pencil-square "\f14b",
external-link-square "\f14c",
share-square "\f14d",
compass "\f14e",
caret-square-o-down "\f150",
caret-square-o-up "\f151",
caret-square-o-right "\f152",
eur "\f153",
gbp "\f154",
usd "\f155",
inr "\f156",
jpy "\f157",
rub "\f158",
ruble "\f158",
rouble "\f158",
krw "\f159",
btc "\f15a",
file "\f15b",
file-text "\f15c",
sort-alpha-asc "\f15d",
sort-alpha-desc "\f15e",
sort-amount-asc "\f160",
sort-amount-desc "\f161",
sort-numeric-asc "\f162",
sort-numeric-desc "\f163",
thumbs-up "\f164",
thumbs-down "\f165",
youtube-square "\f166",
youtube "\f167",
xing "\f168",
xing-square "\f169",
youtube-play "\f16a",
dropbox "\f16b",
stack-overflow "\f16c",
instagram "\f16d",
flickr "\f16e",
adn "\f170",
bitbucket "\f171",
bitbucket-square "\f172",
tumblr "\f173",
tumblr-square "\f174",
long-arrow-down "\f175",
long-arrow-up "\f176",
long-arrow-left "\f177",
long-arrow-right "\f178",
apple "\f179",
windows "\f17a",
android "\f17b",
linux "\f17c",
dribbble "\f17d",
skype "\f17e",
foursquare "\f180",
trello "\f181",
female "\f182",
male "\f183",
gittip "\f184",
sun-o "\f185",
moon-o "\f186",
archive "\f187",
bug "\f188",
vk "\f189",
weibo "\f18a",
renren "\f18b",
pagelines "\f18c",
stack-exchange "\f18d",
arrow-circle-o-right "\f18e",
arrow-circle-o-left "\f190",
caret-square-o-left "\f191",
toggle-left "\f191",
dot-circle-o "\f192",
wheelchair "\f193",
vimeo-square "\f194",
try "\f195",
plus-square-o "\f196";
在这里,每一个图标我们都是用icon-
定义类名,比如说icon-glass
。那么了为节约时间,在变量中我们特意定义了一个默认变量:
$fa-css-prefix: icon- !default;
另外为了调用字体和字体文件方便,因此还定义了另外两个变量:
$fa-family-name: "FontAwesome" !default;
$file-path: "../../fonts/fontawesome-webfont" !default;
这样字体font-family
定义了名称为“FontAwesome”,而且指定了一个变量$file-path
来引用字体文件路径。特别需要注意的是,需要根据项目指定不同的路径。如果您要是使用compass的话,可以通过config.rb
文件来指定这个路径。不过这里对此不做过多的描述。
变量$icons
是我们最需要的,像其他程序一样,通过以key=>value
方式定义了所有图标需要的实体编码。并以数组方式赋值给变量$icons
。
要使用字体图标,就离不开@font-face
。使用@font-face
主要是引用字体,调用特定的字体,这也是最基础的。在此,我们通过定义一个mixin,在需要的就时候使用。
@mixin font-face($font-family,$file-path,$font-weight: normal,$font-style: normal,$asset-pipeline:false){
@font-face {
font: {
family: $font-family;
weight: $font-weight;
style: $font-style;
}
@if $asset-pipeline == true {
src: font-url("#{$file-path}.eot");
src: font-url("#{$file-path}.eot?#iefix") format("embedded-opentype"),
font-url("#{$file-path}.woff") format("woff"),
font-url("#{$file-path}.ttf") format("truetype"),
font-url("#{$file-path}.svg##{$font-family}") format("svg");
}
@else {
src: url("#{$file-path}.eot");
src: url("#{$file-path}.eot?#iefix") format("embedded-opentype"),
url("#{$file-path}.woff") format("woff"),
url("#{$file-path}.ttf") format("truetype"),
url("#{$file-path}.svg##{$font-family}") format("svg");
}
}
}
在font-face
的mixin中,我们传了几个参数给他:
normal
;normal
;asset-pipeline
用来替代app/assets/fonts
下的fonts。这里也传递了一个参数true
。定义好font-face
的mixin时,在需要使用@font-face时,只需要通过@include
来调用:
@include font-face($fa-family-name,$file-path,normal,normal,$asset-pipeline:false);
在调用的时候也指定了mixin的参数:
_variables.scss
中定义的变量,其值为“FontAwesome”;_variables.scss
中定义的变量,其值为../../fonts/fontawesome-webfont
,具体路径需要根据自身项目字体文件的相对路径来进行设置;font-weight
和font-style
,并且值都为normal
;false
,表示不使用Rails下指定的字体。其在font-face
当中会调用下面对应的代码:
src: url("#{$file-path}.eot");
src: url("#{$file-path}.eot?#iefix") format("embedded-opentype"),
url("#{$file-path}.woff") format("woff"),
url("#{$file-path}.ttf") format("truetype"),
url("#{$file-path}.svg##{$font-family}") format("svg");
上面代码编译出来的CSS:
@font-face {
font-family: "FontAwesome";
font-weight: normal;
font-style: normal;
src: url("../../fonts/fontawesome-webfont.eot");
src: url("../../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),
url("../../fonts/fontawesome-webfont.woff") format("woff"),
url("../../fonts/fontawesome-webfont.ttf") format("truetype"),
url("../../fonts/fontawesome-webfont.svg#FontAwesome") format("svg");
}
在Font Awesome中,样式都是通过元素的伪类:before
来制作icon样式,如下所示:
display: inline-block;
font-family: "FontAwesome";
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; }
同时为每个不同的icon调用不同的实体编码:
.icon-glass:before {
content: "\f000"; }
接下来,我们就需要定义一个mixin来实现上述代码等同功能。在这个示例中,定义了icon
的mixin。
@mixin icon($position: "before",$styles:true,$icon:false) {
&:#{$position} {
@if $icon {
content: match($icons, $icon);
}
@if $styles {
display: inline-block;
font: {
family: $fa-family-name;
style: normal;
weight: normal;
}
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@content;
}
}
在整个icon的mixin中,也设置了三个参数:
:before
。如果你需要放置在元素后面的时候,调用时,可以使用:after
。稍后我们可以演示一下。true
,将会调用@if $styles{}
中带有的样式;false
,如果参数为指定的值时,会自动通过match()
函数给对应的图标匹配一个实体编码,并赋值给content
。在整个mixin中,还调用了@content
,其主要功能就是。如果你想给某个图标设置不同样式时,可以通过他来引用其他样式。
定义好这个mixin,我们就可以通过@include icon
和附有具体参数来实现需要的效果:
[class^="#{$fa-css-prefix}"],
[class*="#{$fa-css-prefix}"] {
@include icon;
}
上面指的icon定义在:before
上,并且指定默认样式,但不引用具体的实体编码,编译出来的CSS如下:
display: inline-block;
font-family: "FontAwesome";
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; }
每个图标都需要对应的实体编码,字体图标才会起效果,比如说icon-glass
对应的是"\f000"
,这个时候可以按下面的方式调用:
.#{$fa-css-prefix}glass{
@include icon("before",false,"glass");
}
编译出来的CSS:
.icon-glass:before {
content: "\f000"; }
很多时候,你可能想让图标放在后面,那么我们可稍做修改来实现:
.#{$fa-css-prefix}music{
@include icon("after",false,"music");
}
编译出来的CSS:
.icon-music:after {
content: "\f001"; }
也有的时候,你的图标没有像前面所示的有一个公用的样式(当然这种情况不会存在),这里为了演示说明icon
的功能,我们来做一个示例:
.#{$fa-css-prefix}glass{
@include icon("before",true,"glass");
}
编译出来的CSS:
.icon-glass:before {
content: "\f000";
display: inline-block;
font-family: "FontAwesome";
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; }
当然,你为了给某个图标有不同的样式,比如说图标更大,或者带有阴影之类,可以通过icon
的mixin中的@content
功能来实现:
.#{$fa-css-prefix}glass{
@include icon("before",false,"glass"){
font-size: 2rem;
color: green;
text-shadow: 1px 1px rgba(0,0,0,.5);
};
}
编译出来的CSS:
.icon-glass:before {
content: "\f000";
font-size: 2rem;
color: green;
text-shadow: 1px 1px rgba(0, 0, 0, 0.5); }
这也就实现也文章开头所说的,按需开启需要的icons,不会让你的样式文件调用不需要的图标样式。好处就不多说了,上面演示的示例更说明了一切。
实现按需开启icon功能,其中macth函数功不可没。因为在Sass中没有类似于map功能的函数。这样一来,就无法像其他程序语言一样,通过key
找到其对应的value
值。这样一来,按需开启图标一切都是浮云。
不过还好,Hugo大师在Sass中创建了一个match
函数,用来模拟map的功能:
@function match($haystack,$needle){
@each $item in $haystack {
$index: index($item, $needle);
@if $index {
$return: if($index == 1, 2, $index);
@return nth($item, $return);
}
}
@return false;
}
详细介绍,请点击Mapping with nested lists。
话又说回来,有时候你的可能需要使用很多很多的icons图标,几乎是将里面的图标都用到了,你可能会说,前面的按需开启的方式又会让你觉得不方便,很痛苦。其实不用担心,我们可以定义另一个mixin,并给这个mixin定认一个开关,需要的时候我就开启他,不需要的时候我就不开启他。
在这个get-icons中有两个最为关键,第一给这个mixin定义了一个参数$All-icons
,并且默认传参数false
,表示默认不开启。另外也个最重要的是通过Sass的@each
函数来做循环处理。这个@each
主要是针对于数组变量$icons
的变量值进行遍历循环。具体代码如下所示:
@mixin get-icons($All-icons:false) {
@if $All-icons {
@each $icon in $icons {
$name: nth($icon, 1);
.#{$fa-css-prefix}#{$name}{
@include icon("before",false,$name);
}
}
}
}
有了这个get-icons
的mixin,如果你想开启变量$icons
指定的所有图标的时候,你只需要按下面的方式来引用:
@include get-icons(true);
编译出来的CSS:
.icon-glass:before {
content: "\f000"; }
.
.
.
.icon-plus-square-o:before {
content: "\f196"; }
有了这个模块,就算你不使用Font Awesome字体图标,你也可以快速的完成。你唯一需要修改的就是变量文件_variables.scss
对应的几个变量:
修改完成后,其他调用方式如上面所示。当然你的结构中需要有类似下面这样的结构,并且命名要和$icons
中的key
值对应起来。
<a rel="nofollow" href="http://www.w3cplus.com/icon/rub"><i class="icon icon-rub"></i> icon-rub</a>
当然,如果你不想以icon-
前缀开头时,也你可以换成别的。别如Font Awesome中就换成了:
<a rel="nofollow" href="http://www.w3cplus.com/icon/rub"><i class="fa fa-rub"></i> icon-rub</a>
这个时候你只需要将$fa-css-prefix
变量设置为fa-
就行了。有了这一切是不是让你觉得很方便、很简单了。
本文主要通过Sass实现预编码的特性,实现按需开启需要的图标。并在此以著名的字体图标Font Awesome为例。整个功能的实现主要依赖于创建字体编码数值、定义font-face
、icon
和get-icons
三个mixin和一个match
函数来实现。
如果你有足够多的耐性跟到此处,我想你对这几个功能也有所了解。不过实战是验证真理的最好方式。不仿自己动手一试吧。我想你会有所收获的。如果您有更好的解决方案或者对上面的mixin和function有更好的优化,请在下面的评论中与我们一起分享。
出处:http://www.w3cplus.com/preprocessor/create-font-awesome-font-icons-with-sass.html