Chrome 和 Web Fonts 二三事

1933次阅读  |  发布于5年以前

Chrome 是我的主力浏览器,总得来说用着还算顺手,但也经常遇上一些让人很恼火的地方,例如万恶的滚动条冻结现象、监管不力乱象丛生的扩展、越来越反人类的新标 签页等等。今天要说的是 Chrome(严格说是 webkit)下另外一个严重的问题,与 Web Fonts 有关。

起因

每台电脑都会安装多种字体,网页中可以通过 css 指定页面文本使用哪种字体。Web Fonts 则让浏览器拥有使用从互联网下载的新字体渲染文本的本领。截至到当前,全世界 Alexa 排名前 100 万的网站中,用到 Web Fonts 技术的已经占到 39%。

本文不会介绍如何使用 Web Fonts,本文要讨论的是这样一种场景:

浏览器要渲染使用了 Web 字体的文本,就必须从互联网下载字体。由于网络的不确定性,如果下载字体花费的时间非常久,浏览器该如何处理?

实际上,浏览器能使用的策略并不多,无外乎以下几种:

  1. 先使用系统默认字体渲染文本;等 Web 字体下载完,使用新字体再渲染一次;
  2. 等到 Web 字体下载完成,才渲染文本。也就是字体下载完全阻塞对应文本渲染;
  3. 先跳过文本的渲染;一段时间后,如果 Web 字体仍未下载完,使用系统默认字体渲染文本;等字体下载完,再次渲染;

方案 1 的好处是用户可以第一时间看到文本内容,坏处是:两种字体之间的差异,一定会造成内容抖动。早期的 Firefox 以及现阶段所有 IE 都是采用的这种方案。

方案 2 的好处是完全避免了内容抖动,坏处也很明显:字体下载需要多久,用户就有多久完全看不到文本内容。现阶段基于 Webkit 内核的浏览器,如 Chrome 和 Safari 都是如此。

方案 3 则是一个折中方案,如果 Web 字体能在一段时间内加载完,不会有因为字体变换带来的抖动;同时如果加载字体需要很久,也不至于不显示文本。现阶段 Firefox 采用的这种方案。Firefox 默认等 3 秒,可以找到 about:config 中的 gfx.downloadable_fonts.fallback_delay 配置来修改。

实际上,还有人提出第 1、3 两种方案中,如果字体下载完后只是放入缓存,而不是再次渲染,就可以避免内容抖动。但这样会造成用户连续两次访问同一网页,可能看到不 一样的文本渲染效果。到目前为止,没有浏览器采用这种方案。

无论是什么方案,都应该只影响使用了 Web Fonts 的文本渲染,页面上其他元素的渲染不应该受到影响,更不应该停止。但是,在 IE 中,如果 Web Fonts 定义之前有任何 JS 代码,浏览器会停止所有的渲染工作,直到字体下载完成或失败。另外,IE 还会下载页面上定义的全部 Web Fonts 文件,无论是否会被用到。

不知道大家是否遇到过这样的情况:用 Chrome 访问部分网站时,经常图片都加载完了,源代码也是完整的,就是页面上一个字都没有,而 Firefox 没这个问题。看到这里,大家应该都明白了:这很有可能是因为字体文件那个请求迟迟得不到响应造成的。出现这种情况时,点击 Chrome 的停止按钮,通常文字就能出来。原理很简单:手动告诉浏览器不要傻等 Web Fonts 了,马上使用默认字体渲染。更彻底的解决方案是换用稳定可靠的网络来访问这些网站(如:googleusercontent.com)。

转机

虽然以上描述的问题不能完全怪 Chrome,但 Chrome 的做法确实不太合理。通常,使用 Web Fonts 只是为了给用户带来更好的视觉体验,而让用户 更快的看到页面内容才应该是优先考虑的。这种为了更好的效果(以及避免内容抖动)而降低可用性的做法,实际上是在伤害用户体验。

下面这个表格,描述了字体大小分布,以及不同比例用户加载字体文件所需时间:

Web 字体大小 占比 50% 70% 90% 95% 99%

0KB - 10KB

5.47%

136 ms

264 ms

785 ms

1.44 s

5.05 s

10KB - 50KB

77.55%

111 ms

259 ms

892 ms

1.69 s

6.43 s

50KB - 100KB

14.00%

167 ms

882 ms

1.31 s

2.54 s

9.74 s

100KB - 1MB

2.96%

198 ms

534 ms

2.06 s

4.19 s

10+ s

1MB+

0.02%

370 ms

969 ms

4.22 s

9.21 s

10+ s

可以看到,大部分字体文件都在 100kb 以下,这时 95% 的用户都能在 3s 内下载完。同时也可以看到,仍然有一部分用户需要很久才能下载完字体,这意味着如果他们用的是 Chrome 或 Safari,很长一段时间内他们看到的页面上很可能没有任何文字。

幸好 Chrome 的开发人员也意识到了这一点,很早就开始了对这个问题的讨论。并且,从 Chrome 35(当前还是 dev 版)开始,Chrome 采用了跟 Firefox 一样的策略:对于使用了 Web Fonts 的文本,如果三秒后字体还没加载完,用默认字体渲染;等字体加载完成,使用新字体再次渲染。对照上面的表格,这个策略十分合理,希望 Safari 也能跟进。

尾声

记得 Web Fonts 这项技术刚出来的时候,大家就讨论过中文 Web 字体面临的难题。相比英文字体几十 kb 的大小,中文字体少说好几 M 的身材很容易让人望而却步。好在聪明的同学们很快发现,我们可以为页面上少量需要特别设计的文字定制字体;我们还可以把 Web Fonts 用在实现网站小图标上。这样,字体文件大小可以得到控制。但本文提到的阻塞 Webkit 渲染文本的问题不容忽视,所以有一些建议供大家参考:

  1. 不滥用 Web Fonts(任何新技术都不要滥用!);
  2. 在所有 JS 代码之前定义 Web Fonts(否则在 IE 中,字体文件的加载会阻塞所有界面渲染);
  3. 不要定义不会被用到的 Web Fonts(IE 会加载它们);
  4. 常规的静态资源优化手段也要用在 Web Fonts 上(缓存、GZip 等等);
  5. 对于不同业务用到的相同 Web Fonts,使用同一个地址(类似 JS 公共库托管,同样是为了尽可能利用浏览器缓存),需要特别注意的是:Firefox 下针对非同源字体,需要启用 CORS(通过 Access-Control-Allow-Origin 响应头来控制);

专题「浏览器」的其他文章 »

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8