也来谈谈webfont

2018-01-04

开篇

随着设备终端的不断升级,浏览器的支持度越来越高。网页字体的流行也是必然的趋势,他的课选取,可搜索,可缩放,适配度高以及高性能、良好用户体验等优势让它一跃成为网页前端们实现设计师天马行空的设计图首选。
今天我们就来介绍一下webfont及其应用,顺便讲讲怎么优化webfont。

介绍

简而言之,webfont就是可以让网页使用在线字体的一种技术手段。在此之前设计师在设计稿当中使用的一些特殊字体由于在别人的设备里没有这个字体而无法显示预想的效果,我们的解决方案是用图片来替换特殊字体,webfont的出现这个问题就引刃而解了。

它通过 CSS的@font-face语句引入在线字体,使用CSS选择器指定运用字体的文本。目前网络上使用的字体格式有四种EOTTTFWOFFWOFF2

支持情况如下:

  • WOFF 2.0 提供给支持它的浏览器(对许多浏览器来说尚未实现)。
  • WOFF 支持大多数浏览器。
  • TTF 支持旧 Android(4.4 版以下)浏览器。
  • EOT 支持旧 IE(IE9 版以下)浏览器。

注:从技术角度来讲还有一种格式,即SVG字体,但IE和Firefox从不支持它,并且好像现在的Chrome也放弃了对他的支持,所以暂且就忽略它了。

font-face

css3推出了一个at-rule属性@font-face,来指定特定字体资源的位置、样式特性及其支持的 Unicode 子集。

语法如下:

1
2
3
4
5
6
7
8
9
10
11
@font-face {
[ font-family: <family-name>; ] ||
[ src: [ <url> [ format(<string>#) ]? | <font-face-name> ]#; ] ||
[ unicode-range: <urange>#; ] ||
[ font-variant: <font-variant>; ] ||
[ font-feature-settings: normal | <feature-tag-value>#; ] ||
[ font-variation-settings: normal | [ <string> <number>] # ||
[ font-stretch: <font-stretch>; ] ||
[ font-weight: <weight>; ] ||
[ font-style: <style>; ]
}

font-family: 指定字体的名字,所指定的字体名字将会被用于font或font-family属性;
local() 指令用于引用、加载和使用安装在本地的字体;
format(): 通过该属性来指示URL资源引用的字体格式(可选);
unicode-range: 指定要使用的字体的Unicode子集,从而减小字体载入的体积;
保险评分
比如上图设计师想要的结果,骚气的科技感数字我们要使用DIN字体,但是DIN字体不是所有设备都支持所以我们打算让他支持:

1
2
3
4
5
6
7
8
9
10
@font-face {
font-family: DIN;
font-style: normal;
font-weight: 400;
src: url(../assets/font/DIN_Alternate_Bold.eot);
src: local("DIN Alternate"),
url(../assets/font/DIN_Alternate_Bold.woff) format("woff"),
url(../assets/font/DIN_Alternate_Bold.ttf) format("truetype"),
url(../assets/font/DIN_Alternate_Bold.svg#DINAlternateBold) format("svg")
}

当浏览器察觉到本地没有DIN字体的时候,他会按照指定的顺序循环访问提供的资源列表,如果存在一个format格式提示则先检查是否支持,如果支持就加载该资源,如果不支持则跳过进入下一个格式提示,如果不存在格式提示则不论如何会尝试加载相应的资源。

性能优化

压缩

字体是字形的集合,其中的每个字形都是一组描述字母形状的路径。每种不同字形,往往包含了大量的共同信息,这些信息是可以压缩的。
常见的压缩方式是:GZIP及其他兼容的压缩模式:

  • EOT 和 TTF 格式默认情况下不进行压缩,你可以在服务器开启GZIP进行压缩;
  • WOFF 具有内建压缩
  • WOFF2 采用自定义预处理和压缩算法,提供的文件大小压缩效率比其他格式高大约 30%
    你可以选择其他的压缩方式来减小字体的体积,但要注意做好浏览器测试。

    unicode-range

    利用unicode-range指定编码子集,可以大大减小字体的体积。使用方法有:

  • 指定单一的字符编码用逗号隔开(例如 U+416)
  • 间隔范围 用横杠- 表示代码的起始,例如 (U+400-4ff)
  • 通配符(例如 U+4??)?代表任何16进制数字
    上述三者可以配合使用,并用逗号隔开。
    注:有时候有些浏览器对unicode-range支持的不好,这个时候我们就需要对所使用的字体进行手动的选取子集。网络上很多第三方工具 如fonttools 字蛛等。

    font-display

    注:这是最新的属性,还没达到可使用标准(目前Safari还不支持,Chrome部分版本支持)
    这是最近刚刚提出来的一个方案,就为了解决字体渲染空白问题,说这个之前我们先来讲讲网页字体的加载和渲染问题。

    主要诱因是浏览器在构建渲染树(DOM和CSSOM树)之前会延迟字体请求,因为浏览器必须构建万渲染树之后才能知道使用哪些字体来渲染文本,同时在获取到构建渲染树关键资源之前可能会阻止浏览器渲染文本(网页内容的首次渲染和字体资源加载之间的“竞赛”时,浏览器会产生遗漏渲染所有文本的渲染 注意是所有)。当然对于空白问题在不同浏览器的表现不同,比如Safari会在字体下载完成之前都阻断文本渲染,而chrome会等待最多三秒开始启用后背字体并在下载完成后重渲染。总结下来就下面这个图:

    在Block阶段浏览器使用不可见字体渲染文本(出现空白渲染);到了Swap阶段浏览器使用后备字体(sans-serif)渲染文本;在Failure这个阶段意味着字体下载失败,浏览器将一只延用后背字体。
    目前的问题在于我们没法控制这些阶段的时间长短以及当其中一个阶段失败后怎么处理,font-display给了这种可能。它有四个值:block, swap, fallback 以及 optional,当然也有auto其表现和block一致。
    各个属性值表现如下图:

    • font-display: block ,文本将被阻断一段时间(长短看浏览器,新版Safari, Chrome ,Firefox是3秒;IE为0秒可视为没有block阶段;旧版本Safari无限长时间),会出现所谓的空白渲染问题(FOIT)
    • font-display: swap ,文本将不会出现block阶段,文本会立即用后背字体展现知道所需字体加载完成。会出现字体切换效果(FOUT)
    • font-display: fallback ,表现介于block和swap之间。空白期缩短至100ms,然后切换到后备字体直到所需字体加载完成
    • font-display: optional ,表现和fallback类似,区别在于它会自动的去根据网络的速度(如2g网络)来决定是否切换字体。

    此属性使用时,我们需要根据具体情况来使用:如果我们使用webfont来做icon图时候,我们是不可能接受fallback的,所以我们需要使用font-display:block。

    更多

    想要说的是@font-face 下面提到的属性(如font-weight,font-style等)对于性能优化来说也是很重要的,他会影响浏览器匹配资源和加载资源的效率以及视觉一致性等因素,所以尽可能准确的给浏览器于明确的指示。
    当然了其他的优化方案还有很多,包括HTTP缓存,利用FontLoading API优化起加载和渲染等自行探索吧。

结语

2017年过去了,本来想写个总结的。但人在欧洲的火车上,思绪全不在这上面。眨巴眼的功夫2018年已经悄然开始三两天了,杂货铺开篇也快两年了,由于17年后期也懒了许多文章一直没跟上,粉丝也没达到年初一万的小目标,但也9900有余,专栏共收录文章112篇(算上这,113篇)。在此感谢作者天方夜,于秋,谢然,染陌同学,蒋欢,林鑫,SimplyY ,Awee,胡子大哈,吴成琦,LeviDing ,黄俊亮 ,林列欢 ,危险 ,ahonn 等(排名不分先后,可能有纰漏见谅)的投稿,为热爱前端的同学们带来知识的饕餮大餐,没有你们的支持杂货铺也不会受到如此多关注。同时也感谢成千上万的粉丝一如即往的支持,你们是我坚持的动力。在知乎里遇到大家是我的荣幸,希望在接下来的一年里我们能延续这样的默契和友谊,为了这份纯粹的爱好共同进步。