前端开发者学堂 - fedev.cn

font-display的用法

发布于 若水

如果你已经对CSS有了一定的了解,也许你之前已经掌握了一些字体加载的方法,那么你使用过font-display吗?

font-display是CSS中新添加的属性,它能实现之前类似于Font Loading APIBram Stein's Font Face Observer这种第三方脚本实现的功能。

如果这是你第一次接触这类知识,那也没有关系,我们会先简单介绍一下浏览器加载字体的默认方法。

浏览器是如何加载字体的?

浏览器经常会出现一些出乎我们意料的问题,而字体的加载就是其中之一。大多数浏览器在自定义字体还未下载之前会先隐藏文本。这就是大家所说的FOIT(Flash of Invisible Text)

浏览器是如何加载字体的?

虽然现在在一般加载的过程中你可能不会看到这种情况,不过我们可以通过限制连接速度来观测浏览器的默认行为。可以看出,大部分浏览器会隐藏文本长达3s直到字体加载完成。其他浏览器,比如Safari会等待更长的时间。有些甚至永远都不会显示文本。

目前我们解决这类问题的方法是使用JavaScript-based脚本(比如 Font Face Observer)来跟踪字体是否被下载。在字体被下载完成前,我们使用浏览器自带的字体来显示文本,直到我们通过JavaScript探测到字体下载完成,我们给我们的文档添加一个CSS类来应用我们的自定义字体。这种方法我们之前有过详细介绍。比如,假设你有一个段落需要使用Open Sans Regular,那你就需要按以下的方法来实现:

p {
    font-family: "Arial", "Helvetica", sans-serif;
}

在字体下载的时候,会先使用Arial 或者 Helvetica(这取决于你的浏览器支持什么字体)来显示文本。当通过JavaScript探测到Open Sans Regular字体下载完成,我们就将fonts-loaded添加到<html>标签上,然后通过编写CSS来使用Open Sans渲染该段落:

.fonts-loaded p {
    font-family: "Open Sans Regular";
}

这个方法虽然能奏效,但是显得相当笨重。这时就有了font-display的用武之地啦。

了解font-display

font-display是一个新的CSS属性,最先是在Chrome 49中进行试验,现在在Opera和Opera for Android中也得到了支持。通过使用这个属性,我们可以看到如何通过一行CSS代码来实现之前通过JavaScript脚本才能实现的功能。

我们在@font-face指令中使用font-display来加载自定义字体。这个属性可以添加以下的值:

  • auto:默认值。典型的浏览器字体加载的行为会发生,也就是使用自定义字体的文本会先被隐藏,直到字体加载结束才会显示。
  • swap:后备文本立即显示直到自定义字体加载完成后再使用自定义字体渲染文本。在大多数情况下,这就是我们所追求的效果。之前提及到的JavaScript脚本实现的功能就基本和这个是一致的。
  • fallback:这个可以说是autoswap的一种折中方式。需要使用自定义字体渲染的文本会在较短的时间(100ms according to Google )不可见,如果自定义字体还没有加载结束,那么就先加载无样式的文本。一旦自定义字体加载结束,那么文本就会被正确赋予样式。
  • optional:效果和fallback几乎一样,都是先在极短的时间内文本不可见,然后再加载无样式的文本。不过optional选项可以让浏览器自由决定是否使用自定义字体,而这个决定很大程度上取决于浏览器的连接速度。如果速度很慢,那你的自定义字体可能就不会被使用。

现在我们已经了解了font-display可设置的值,那我们就可以在@font-face规则中使用它了。下面是使用swap为值的一个例子:

@font-face {
  font-family: "Open Sans Regular";
  font-weight: 400;
  font-style: normal;
  src: url("fonts/OpenSans-Regular-BasicLatin.woff2") format("woff2");
  font-display: swap;
}

在这个例子里我们通过只使用WOFF2文件来缩写字体。另外我们使用了swap作为font-display的值,页面的加载情况将如下图所示:

浏览器是如何加载字体的?

当我们使用JavaScript来控制字体加载的时候,我们希望确保文本一开始默认就是可见的,当自定义字体下载完毕后载应用自定义字体渲染文本。

那后备文字是什么呢?当你给一个元素指定font-family时,你可以指定一系列的字体,并通过逗号来分隔这些字体。在自定义字体后的那些字体如果能得到浏览器的支持,那么这个字体就是后备字体:

p {
    font-family: "Open Sans Regular", "Helvetica", "Arial", sans-serif;
}

在上面这个例子中,自定义字体是Open Sans Regular,系统字体是 HelveticaArial。当我们将font-display的值设置为swap的时候,最开始会先使用系统字体来显示文字,当自定义字体下载完毕后,自定义字体就会取代系统字体。当font-display的值设置为fallbackoptional时,显示的字体将会取决于在决定如何处理自定义字体时系统堆栈中的后备字体是什么字体。

大多数时候你可以选择使用swap作为属性值

如果你不知道选择那个作为font-display的属性值,你可以选择swap。它不仅提供了自定义字体和内容的可访问性之间的最佳平衡,它还提供了和使用JavaScript脚本相同的字体加载行为。如果你在页面上有想要加载的字体,但是最终也可以不加载,这时你就可以考虑使用fallback或者optional作为font-display的值。

如果不支持font-display怎么办?

font-display的唯一缺陷就是还没有得到广泛的支持。在这种情况下你有两个选择:

  • 就只使用font-display属性。如果浏览器不支持这个属性,它只是没有办法使用该属性提供的便利之处,但是它不会破坏任何东西。
  • 你可以既提供font-display属性也提供一个替代方案。如果时间和资源允许,推荐你选择这个方案。

如果你决定选择第二个选项,那么你首先需要去判断浏览器是否支持font-display属性。很幸运的是这是件很容易做到的事:

if ("fontDisplay" in document.body.style === false) {
    /* JavaScript font loading logic goes here. */
}

通过判断之后的反馈,我们可以决定我们应该怎么做,是否应该使用第三方JavaScript脚本,比如Font Face Observer,或者是使用在Firefox, Chrome 和 Opera支持的字体加载API。

if ("fontDisplay" in document.body.style === false) {
  if("fonts" in document) {
      document.fonts.load("1em Open Sans Regular");
      document.fonts.ready.then(function(fontFaceSet){
          document.documentElement.className += " fonts-loaded";
      })
  }
}

在这里我们使用了字体加载API来为我们解决这个问题。一旦API知道字体加载完毕,就可以在<html>标签上添加fonts-loaded类,然后我们就可以通过编写CSS来逐步应用自定义字体。

p {
    font-family: "Helvetica", "Arial", sans-serif;
}

.fonts-loaded p {
    font-family: "Open Sans Regular";
}

很显然,我们肯定愿意使用一行CSS代码就能解决我们的需求,但是我们至少也需要有能力再需要的时候提供替代方案。随着时间的推移,我们可以预期这种解决方案,如字体加载API,在其他浏览器也将可以使用。

如果使用的是第三方字体供应商呢?

如果你使用的是第三方字体供应商,比如Google Fonts 或者 TypeKit,你能做的事情是很有限的。font-display属性必须在@font-face指令内使用。因为你不能控制第三方字体供应商的CSS文件,所以你没有办法控制font-display属性更用说给他传递值了。

但是随着时间的推移,这些供应商可能会改变他们的CSS文件来包含font-display属性,或者允许它作为一个可配置的选项。

总之,font-display是一个很受欢迎的属性,除了增强网页样式,它还大大简化了JavaScript中冗余繁杂的任务。如果你使用的是Chrome浏览器,你可以去<chrome://flags/#enable-experimental-web-platform-features>启用实验性网络平台并亲自试一试font-display属性。

本文根据@Jeremy Wagnerfont-display for the Massese》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://css-tricks.com/font-display-masses

若水

在校研究生,计算机相关专业。一个喜欢看书和写作的女孩,热爱前端,享受成长。最喜欢的一句话:宁鸣而死,不默而生。

如需转载,烦请注明出处:https://www.fedev.cn/css/font-display-masses.htmlnike air max 2019 online