如何提高前端性能——字体篇
前言
有时候前端开发需要使用到一些特殊字体,但宿主机上一般都没有安装相应的字体,所以需要将字体文件与前端代码一起打包以及用 CSS 定义使用。本文主要是想回答一个问题:在性能方面,我们可以怎么去优化前端需要加载的字体?
一般优化的思路主要是两方面:
- 缩小字体文件
- 优化字体加载的方式
缩小字体文件
字体文件一般都比较大,动不动就几兆、十几兆的,所以我们优化的步是想办法缩减字体文件的大小。
使用特定的字体格式——WOFF/WOFF2#
常见的字体格式有TTF(TrueType Font)、OTF(OpenType Font)、EOT(Embedded Open Type)、WOFF(Web Open Font Format)和WOFF2。
更详细的介绍字体的文章可以看:Web 字体简介: TTF, OTF, WOFF, EOT & SVG
简单来说,TTF和OTF都是没有压缩,所以这两个格式的字体文件会更大;EOT字体格式只有IE浏览器支持;SVG对文本的支持不够好…等等,因此使用WOFF可以说是前端开发的佳选择了。(还有专家建议只用WOFF2字体,原文如下)
In fact, we think it is also time to proclaim: Use only WOFF2 and forget about everything else.
This will simplify your CSS and workflow massively and also prevents any accidental double or incorrect font downloads. WOFF2 is now supported everywhere. So, unless you need to support really ancient browsers, just use WOFF2. If you can't, consider not serving any web fonts to those older browsers at all. This will not be a problem if you have a robust fallback strategy in place. Visitors on older browsers will simply see your fallback fonts.
Bram Stein, from the 2022 Web Almanac
WOFF的优点主要有两个:
- 字体经过压缩,文件大小一般比TTF小40%;
- 主流的浏览器新版本都支持此格式;
WOFF2是WOFF的升级版,压缩率在此基础上提高了30%。
按需压缩字体#
有时候前端页面中需要使用特殊字体的文本是固定的,那么就可以利用font-spider
(同类开源库还有fontmin
等)去将文本所对应的字体子集提取出来,生成一个新的子集包代替原本的全量字体包,这样即可大大减小字体文件,提高性能。
使用方式#
官方指南
font-spider 可以自动分析出页面中使用过的字体并进行按需压缩,也就是说,如果页面中的文本有改动就需要重新压缩。这种压缩方式比较适合页面的文字一般不会改动的场景。
下面是我对某个字体文件的提取对比,在这个情境中我的网站只有数字部分用到了这个字体,所以没必要把整个字体文件都打包进去,所以我使用了font-spider把字体文件中的数字部分提取出来了。
字体压缩前后的效果对比:
优化字体加载的方式
下图展示了浏览器绘制页面的过程:
从图片我们可以看出,浏览器从请求html文档到呈现文本,中间还有好几个步骤。因此字体的请求会比其他关键资源请求之后延迟很长时间,并且,在获取到字体资源前,浏览器处理文本的方式也各不相同。
在加载网页上的字体时,浏览器一般会有两种选择:
- 推迟渲染字体的时间直到字体资源下载完成(导致FOIT)。
- 在下载好字体资源前用备用字体展示该内容(导致FOUT)。
减少浏览器请求的次数#
虽然在使用非默认系统字体时,用户一般不会在本地安装相应的文件,但是开发者仍然需要考虑到这种情况。在定义 font-face
时,可以使用 local()
先请求本地字体,示例代码如下:
@font-face {
font-family: 'Awesome Font';
font-style: normal;
font-weight: 400;
src: local('Awesome Font'),
url('/fonts/awesome.woff2') format('woff2'),
url('/fonts/awesome.woff') format('woff'),
url('/fonts/awesome.ttf') format('truetype'),
url('/fonts/awesome.eot') format('embedded-opentype');
}
对于这段代码,浏览器会按照下述顺序去请求资源:
- 浏览器渲染页面的DOM树,判断出需要加载哪个字体。
- 循环判断每个需要的字体是否可以本地使用。
- 如果本地没有该字体,就按照代码顺序去请求
url()
中定义的字体资源。- 如果有定义
format
,那么浏览器在下载字体资源前会先检查自己支不支持该格式,如果不支持,则继续请求下一行代码定义的字体资源。 - 如果没有定义
format
,则直接下载该资源。
- 如果有定义
使用 font-display#
虽然不同的浏览器会对字体加载有不同的处理方式,但是开发者可以用 font-display
去控制这个行为。
font-display
在 CSS 层面上提供了此类问题的解决方法,它提供了五个属性:
- auto:使用浏览器默认的行为;
- block:浏览器首先使用隐形文字替代页面上的文字,并等待字体加载完成再显示;
- swap:如果设定的字体还未可用,浏览器将首先使用备用字体显示,当设定的字体加载完成后替换备用字体;
- fallback:与
swap
属性值行为上大致相同,但浏览器会给设定的字体设定加载的时间限制,一旦加载所需的时长大于这个限制,设定的字体将不会替换备用字体进行显示。 Webkit 和 Firefox 中设定此时间为 3s;- optional:使用此属性值时,如果设定的字体没有在限制时间内加载完成,当前页面将会一直使用备用字体,并且设定字体继续在后台进行加载,以便下一次浏览时可以直接使用设定的字体。
NimitzDEV,《页面字体闪一下?这两个标准能帮到你》
采用什么样的加载策略取决于字体的重要性、个人审美以及性能考虑等等,因此在此不做推荐,以下是几种主要策略:
性能优先 | 速度优先 | 网络字体优先 | |
---|---|---|---|
推荐值 | optional | swap | block |
优点 | 非常高效,文本呈现时间短。 | 可以保证在使用网络字体的前提下尽早完成字体的渲染。 | 可以大程度确保优先使用网络字体;尽管也会出现布局偏移,但是显示效果比swap的效果更平滑。 |
缺点 | 如果浏览器在限制时间内没有下载完字体,则不会加载网络字体。 | 如果字体请求过久,会导致页面出现FOUT闪烁。 | 这个策略推迟了文本的显示时间,导致FOIT闪烁。 |
相关文章