在网页开发里,字体的加载和显示可是个重要的事儿。有时候我们打开一个网页,字体的显示效果可能会不尽如人意,比如出现字体闪烁或者短暂不显示文字的情况。这其实就是 FOIT(无样式内容闪烁)和 FOUT(无样式文本闪烁)的问题。下面咱就好好唠唠怎么优化 CSS 字体加载,解决这俩问题。

一、FOIT 和 FOUT 问题是啥

1. FOIT 问题

FOIT 就是无样式内容闪烁。当浏览器在加载自定义字体时,如果字体还没加载好,页面上对应的文字就完全不显示,直到字体加载完成才一下子显示出来。想象一下,你打开一个网页,结果有那么一小段时间,页面上部分文字的地方就是空白,等过了一会儿文字才突然冒出来,这体验可太糟心了。

2. FOUT 问题

FOUT 是无样式文本闪烁。在这种情况下,当自定义字体还在加载时,页面会先用系统默认字体显示文字。等自定义字体加载完成后,再把文字替换成自定义字体。这样就会出现文字样式突然变化的情况,就好像文字“闪”了一下,也会影响用户的阅读体验。

二、传统字体加载方式的问题

传统的 CSS 字体加载方式,就是直接在 CSS 文件里用 @font-face 规则来引入自定义字体。看下面这个例子(CSS 技术栈):

/* 引入自定义字体 */
@font-face {
    font-family: 'MyCustomFont';
    src: url('path/to/my-custom-font.ttf') format('truetype');
}

/* 使用自定义字体 */
body {
    font-family: 'MyCustomFont', Arial, sans-serif;
}

这种方式很简单直接,但是它有个大问题,就是容易出现 FOIT 或者 FOUT 问题。因为浏览器在解析到 @font-face 规则时,会去加载对应的字体文件。在字体文件加载完成之前,它不知道该怎么显示文字,就会按照前面说的 FOIT 或者 FOUT 的情况来处理。

三、优化方案之字体显示策略

1. font-display 属性

CSS3 引入了 font-display 属性,这个属性可以控制字体在加载过程中的显示行为。它有几个不同的值,咱一个一个来说。

(1)auto

这是默认值,浏览器会按照自己的规则来处理字体加载和显示,还是容易出现 FOIT 或者 FOUT 问题,所以不太推荐。

(2)block

使用这个值时,浏览器会有一个短暂的“阻塞期”。在这个阻塞期内,如果字体还没加载好,文字就不显示(FOIT 情况)。阻塞期结束后,如果字体还没加载好,就用系统默认字体显示,等字体加载完成后再替换。看下面的例子(CSS 技术栈):

@font-face {
    font-family: 'MyCustomFont';
    src: url('path/to/my-custom-font.ttf') format('truetype');
    font-display: block;
}

body {
    font-family: 'MyCustomFont', Arial, sans-serif;
}

(3)swap

这个值就比较友好了。当浏览器使用 swap 时,会立即用系统默认字体显示文字,等自定义字体加载完成后再替换。这样就避免了 FOIT 问题,虽然还是有 FOUT 问题,但至少不会出现文字空白的情况。示例如下(CSS 技术栈):

@font-face {
    font-family: 'MyCustomFont';
    src: url('path/to/my-custom-font.ttf') format('truetype');
    font-display: swap;
}

body {
    font-family: 'MyCustomFont', Arial, sans-serif;
}

(4)fallback

fallback 有一个非常短的阻塞期。在阻塞期内,如果字体加载好,就正常显示自定义字体;如果没加载好,就用系统默认字体显示,并且后续不会再替换成自定义字体,除非重新加载页面。示例如下(CSS 技术栈):

@font-face {
    font-family: 'MyCustomFont';
    src: url('path/to/my-custom-font.ttf') format('truetype');
    font-display: fallback;
}

body {
    font-family: 'MyCustomFont', Arial, sans-serif;
}

(5)optional

fallback 类似,但是阻塞期更短。浏览器会根据网络情况和性能来决定是否使用自定义字体。如果网络不好或者性能不佳,就可能直接使用系统默认字体,不加载自定义字体了。示例如下(CSS 技术栈):

@font-face {
    font-family: 'MyCustomFont';
    src: url('path/to/my-custom-font.ttf') format('truetype');
    font-display: optional;
}

body {
    font-family: 'MyCustomFont', Arial, sans-serif;
}

2. 预加载字体

我们还可以使用 HTML 的 <link> 标签来预加载字体文件。这样浏览器会在解析 CSS 之前就开始加载字体文件,减少字体加载的时间。示例如下(HTML 技术栈):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 预加载字体文件 -->
    <link rel="preload" href="path/to/my-custom-font.ttf" as="font" type="font/ttf" crossorigin>
    <link rel="stylesheet" href="styles.css">
    <title>Document</title>
</head>
<body>
    <!-- 页面内容 -->
</body>
</html>

这里的 crossorigin 属性是必须的,因为字体文件通常是跨域加载的。

四、优化方案之字体文件处理

1. 选择合适的字体格式

不同的字体格式在不同的浏览器中支持情况不一样。常见的字体格式有 TTF、OTF、WOFF、WOFF2 等。其中,WOFF 和 WOFF2 是专门为网络使用设计的字体格式,它们的文件大小比 TTF 和 OTF 小很多,加载速度更快。所以,我们优先使用 WOFF2 格式,如果浏览器不支持,再降级到 WOFF 格式。示例如下(CSS 技术栈):

@font-face {
    font-family: 'MyCustomFont';
    src: url('path/to/my-custom-font.woff2') format('woff2'),
         url('path/to/my-custom-font.woff') format('woff');
}

body {
    font-family: 'MyCustomFont', Arial, sans-serif;
}

2. 子集化字体

很多时候,我们使用的字体文件包含了大量我们用不到的字符。比如,一个中文字体文件可能包含了所有的中文字符,但我们的网页可能只用到了其中一部分。这时候,我们就可以对字体文件进行子集化处理,只保留我们需要的字符。这样可以大大减小字体文件的大小,加快加载速度。可以使用一些工具来进行字体子集化处理,比如 Fonttools 或者 Glyphhanger。

五、应用场景

1. 品牌网站

品牌网站通常非常注重品牌形象的展示,字体是品牌形象的一部分。在品牌网站上使用自定义字体可以更好地传达品牌特色。但是如果不优化字体加载,出现 FOIT 或者 FOUT 问题,就会影响用户对品牌的印象。所以,在品牌网站上优化 CSS 字体加载是很有必要的。

2. 内容类网站

内容类网站,比如新闻网站、博客网站等,用户主要是来阅读内容的。如果在阅读过程中出现字体闪烁或者文字空白的情况,会严重影响用户的阅读体验。通过优化字体加载,可以让用户更流畅地阅读内容。

六、技术优缺点

1. 优点

(1)提升用户体验

通过解决 FOIT 和 FOUT 问题,用户在浏览网页时不会再遇到文字闪烁或者空白的情况,阅读体验会更加流畅。

(2)加快页面加载速度

选择合适的字体格式和进行子集化处理可以减小字体文件的大小,从而加快页面的加载速度。

(3)更好地展示品牌形象

在品牌网站上使用自定义字体并优化加载,可以更好地展示品牌形象。

2. 缺点

(1)增加开发成本

字体子集化处理需要使用额外的工具,并且需要对字体文件进行处理,这会增加一定的开发成本。

(2)兼容性问题

虽然大多数现代浏览器都支持 font-display 属性和 WOFF2 格式,但还是有一些旧版本的浏览器不支持。在使用这些技术时,需要考虑兼容性问题。

七、注意事项

1. 字体版权问题

在使用自定义字体时,一定要确保字体的版权问题。有些字体是需要付费使用的,如果未经授权使用,可能会面临法律风险。

2. 测试不同浏览器和设备

不同的浏览器和设备对字体加载的处理方式可能会有所不同。所以,在开发完成后,一定要在不同的浏览器和设备上进行测试,确保字体加载正常,没有出现 FOIT 或者 FOUT 问题。

八、文章总结

通过使用 font-display 属性、预加载字体、选择合适的字体格式和进行子集化处理等方法,我们可以有效地优化 CSS 字体加载,解决 FOIT 和 FOUT 问题。在实际开发中,我们要根据具体的应用场景和需求,选择合适的优化方案。同时,也要注意字体版权问题和不同浏览器、设备的兼容性问题。这样,我们就能为用户提供更好的网页浏览体验。