池月

天知道Web字体是什么

池月 · 2016-12-08翻译 · 918阅读 原文链接

在我令人惊讶的2G数据漫游计划中,我和朋友们花了一星期漫游台湾,同时,我们讨论了Web字体。当然,还有猫。那里的人真的很爱猫。 无论如何,关于2G的事情我完全理解,它将需要10秒钟加载完一个页面!最令人愤怒的是,最后的4秒钟就为了等待加载一个有点不一样的非衬线字体,而这期间我只能看着代替内容的下划线!

听好了: 你也不是非得这么做。你也可以缓慢地加载你的字体。而这只要四行JS足矣。即使你是个野心勃勃的人。

为什么你不能不在乎

我已经被关注首次渲染性能的理论彻底洗脑。 (多谢谷歌浏览器开发大会 😘), 我成了“do less & be lazy” 主义的粉丝。 也就是说,如果某件事不是特别重要,那么不需要在页面上优先渲染。

现在进入正题,谈谈字体:文字内容和文字样式,谁更重要?显然,显示一部分内容或者显示丑陋的内容,好过没有内容。当然,我不会和你争论,如果你要做的恰好是不足1%的那种只需要炫酷的视觉体验的APP(这种情况下这篇文章不适用)。

(真诚的提醒: 如果渲染字体不是你最重要的事,你中奖了,我们好好聊聊。)

加载Web字体的时候,你有两件事要做:

  • FOIC (“闪过看不见的内容”) – 当你使用一个本地没有的字体的时候,浏览器会用看不见的墨水渲染内容,当字体下载完成,它会重绘和重排刚刚的内容。 [gif示例]

我讨厌这种情况,相比看见实际内容,我看见的是强调符和下划线还有随机的没有样式的文本。真不优雅!

  • FOUC (“闪过没有样式的内容”) – 超过3秒后,Chrome 会停止等待一个字体(最近,在2G网络下是0秒)。这意味着,它不会显示看不见的墨水,而是用备用字体来渲染内容。当字体下载完成的时候,它会用新字体重绘刚刚展示的内容。 [gif示例]

边注: 在iPhone里, 不存在这种超时的情况, 所以你会出现FOIC的情况 – 你等待整个从“没有文本”到“有所有文本”的状态,中间没有过渡状态。

(这里 是这个demo的代码,我分别在GPRS和2G下在Chrome里测试,这个demo在LTE的表现都很好。所有东西在LTE上表现都很棒。)

阅读材料

很多人都写过关于Web字体的文章,我不想重新写一篇类似的文章。Chrome在这方面已经有了很多改善,通过在2G网络下把等待字体下载的时间下降为0秒,通过font-display属性来工作。

这是我推荐阅读的材料:

  • 这本 网页字体解剖 和这本 讲述浏览器如何使用Web字体。

  • font-display 选项, 以及它如何影响网页字体下载。

  • font-display: optional 关于它为什么这么神奇(如果你不能快速完成,那就不做)。

  • 压缩 下载字体 只保留要使用的字符。

  • 为什么我们要关注Web字体以及如何通过JavaScript来减少FOIT情况的发生,一个叫 字脸观察者的库。

  • 圣战士解决方案 组合 字脸观察者, 异步加载字体包和网页存储。

延迟加载字体

我个人喜欢使用font-display: optional, 但它不是在任何地方都起作用。 有两种延迟加载字体的方法。 再说一次,我并不介意FOUC的情况,因为它让我感觉是一种优化的放大: 先立刻展示内容,之后再赋予特别的字体样式。

<head>
  <style>
    body {
      font-family: 'Arima Madurai', sans-serif;
    }
  </style>
</head>
<body>...</body>
<script>
  // Do this only after we've displayed the initial text.
  document.body.onload = function() {
    var url = 'https://fonts.googleapis.com/css?family=Arima+Madurai:300,400,500';
    loadFont(url);  // hold tight, i tell you below.
  }
</script>

有两种基本方法可以实现loadFont函数。

加载样式表 (阻塞)

有一种对简单网页很有效的简单方法。但是!因为加载/解析样式表会阻塞文档解析/渲染,如果在文档加载后加载很多模块,那么这种方法的表现会有延迟。 [demo]

var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
document.head.appendChild(link);

XHR 样式表 (异步)

如果你关心同步性(实话说,你本应该),你可以发起异步XMLHttpRequest,然后创建一个结点,然后将请求的结果添加进去。 [demo]

var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    var style = document.createElement('style');
    style.innerHTML = xhr.responseText;
    document.head.appendChild(style);
  }
};
xhr.send();

更进一步, 你可以这样做 更进一步的例子 这个方法和之前创建内联样式的方法相似,只不过是创建了外联的样式表。好处是不会受到浏览器缓存的影响。反正我是不相信浏览器的缓存机制。

更新: 显然,这不完美。在快速的LTE连接中, 它会出现FOUC现象。即使像在第一个demo中什么也没做,也会这样。虽然并不会所有人都在LTE连接中,但我觉得你有必要思考这个问题。如果你想要尽量减少FOUC的影响, Helen Holmes 给了一个惊人的谈话 提到了网页排版和性能问题, 她提到你可以尝试用你的备用字体的x-heights去匹配你的目标字体,所以FOUC更优雅。

TL; DR(左对齐;右对齐)

OK。Web字体会使你的博客更漂亮。同时,他们也是缓慢并且恼人的体验,但是如果你需要使用他们,请记住,使你的网站加载速度变快也是你的责任,如果你不能,那么人们在推特上抱怨你的网站是多么的慢是理所当然的事。

(🍹 感谢 Paul Lewis 耐心地听完我所有的问题并给我解释基本的浏览器原理。再次感谢。)

译者池月尚未开通打赏功能

相关文章