CSS @font-face 网页字体加载策略
本文主要介绍网页字体加载策略:
@font-face 用法
CSS @font-face
用户定义网站使用的字体,用法如下:
@font-face {
font-family: 'diyfont';
src: url('diyfont.eot'); /* IE9+ */
src:
url('diyfont.eot?#iefix') format('embedded-opentype'),
/* IE6-IE8 */ url('diyfont.woff') format('woff'),
/* chrome、firefox */ url('diyfont.ttf') format('truetype'),
/* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('diyfont.svg#fontname') format('svg'); /* iOS 4.1- */
}
在浏览器中使用字体需要注意:
- 需要兼容当前的主流浏览器,需同时使用 TureTpe(.ttf)、Web Open Font Format(.woff)、Embedded Open Type(.eot)、SVG(.svg) 四种字体格式。
- 嵌入 HTML 文档的字体是指将 OpenType 字体(压缩的 TrueType 字体)文件映射到客户端系统,用来提供 HTML 文档使用该字体,或取代客户端系统已有的同名字体。即让客户端显示客户端所没有安装的字体。
- .eot(Embedded Open Type) 为 IE 的私有字体格式。Safari3.1 开始支持 .ttf(TrueType) 和 .otf(OpenType)。
- 未来 .woff(Web Open Font Format) 将会取代 .ttf(TrueType) 和 .otf(OpenType) 两种字体格式。
什么时候会下载字体?
上面讲了字体的基本知识,那你有没有想过,字体是在什么时候下载的呢?当我们仅仅在 CSS 中定义如下样式的时候, 页面加载,字体会自动下载吗?
很遗憾,字体并不会下载。 通常情况下,只有当我们的页面元素用到了 @font-face
中定义的字体的情况下,才会下载对应的字体。
注意: 这里我们说了是通常情况,这是因为,IE8 在只要是定义了
@font-face
,即使页面元素没有使用对应的字体,也会下载。
比如在 Firefox 和 IE 9+ 中,遇到如下情况也会下载字体:
<style>
#test {
font-family: Lato;
}
</style>
<div id="test"></div>
有什么特别之处呢?你可能注意到了,这个元素虽然使用到了 font-family: Lato
样式,但是这个元素并没有任何文本啊!!!。按照我们的理想情况,应该是,只有有文字内容才会去下载字体嘛。而这就是 Chrome, Safari (WebKit/Blink 等) 浏览器的行为。
Chrome, Safari (WebKit/Blink 等)浏览器只有在如下类似情况才会去下载字体:
<style>
#test {
font-family: Lato;
}
</style>
<div id="test">这里是有文本的哦</div>
总结不同浏览器下载字体的策略:
- IE8 只要定义了
@font-face
,就会去下载字体,不论实际有没有应用该字体。 - Firefox, IE 9+ 只有定义了
@font-face
并且页面有元素应用了该字体,就会去下载,不论该元素是否有文本内容。 - Chrome, Safari 只有定义了
@font-face
并且页面有元素应用了该字体,并且该元素有文本内容,才会去下载字体。
如果我们的 DOM 元素是通过 JavaScript 动态插入的呢?比如:
const el = document.createElement('div')
el.style.fontFamily = 'open_sansregular'
document.body.appendChild(el)
el.innerHTML = 'Content.'
结果是一样的,它的下载策略如下:
const el = document.createElement('div')
el.style.fontFamily = 'open_sansregular'
/* 到这里,IE8就会开始下载字体 */
document.body.appendChild(el)
/* 只有到这里,Firefox, IE 9+ 才会开始下载字体 */
el.innerHTML = 'Content.'
/* 只有到这里,Chrome, Safari 才会开始下载字体 */
FOIT(Flash of Invisible Text)
FOIT 是浏览器在加载字体的时候的默认表现形式,也就是在字体加载过程中,页面是看不到文本内容的。在现代浏览器中,FOIT 会导致这种现象出现至多 3 秒。FOIT 会导致很差的用户体验,这是我们需要尽量去避免的。
FOUT(Flash of Unstyled Text) 与 font-display 属性
FOUT 意思是在字体加载过程中使用默认的系统字体,字体加载完后显示加载的字体,如果超过了 FOIT(3s) 字体还没加载,则继续使用默认的系统字体。
IE 浏览器和 Edge 不会等待 FOIT 超时才显示默认字体,会立即显示默认字体。FOUT 比 FOIT 好,但是需要注意它引起的 reflow.
那么要想使浏览器有 FOUT 行为,我们需要在设置 @font-face
的时候给它加一个属性:font-display
。font-display
默认是 auto
, 可选属性与含义如下:
- auto: The font display policy is user-agent-defined.
- block: Gives the font face a short block period (3s is recommended in most cases) and an infinite swap period.
- swap: Gives the font face an extremely small block period (100ms or less is recommended in most cases) and an infinite swap period.
- fallback: Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a short swap period (3s is recommended in most cases).
- optional: Gives the font face an extremely small block period (100ms or less is recommended in most cases) and a 0s swap period.
一般设置成 fallback
和 optional
即可。
link preload
在页面加入下面这个代码以便更快的加载字体:
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
通常和最基本的字体用法配合使用
将字体转化为 BASE64
这种方法就是将 @font-face
中定义字体时的路径直接改为字体的 base64 编码。
优点:这种做法的优点是不会产生 FOIT 和 FOUT。所以也不会有 reflow 和 repaint. 缺点:字体转成 base64 也会很大,会影响页面首次加载速度。不支持逗号分隔的形式加载多种格式的字体,只能加载一种格式字体。这导致你为了尽可能保证所有浏览器都可以兼容,通常会指定为 woff 格式,因为 woff 格式兼容性好,但是却没法使用更小体积的 woff2 格式,因为 woff2 格式兼容性差点。
使用 Font Load API + FOUT + class 切换
这种方式是期初并不使用用到 @font-face
的 class
,然后用 Font Load API 加载我们想用的字体,然后切换相应的 CSS 即可。Font Load API 是原生的 API:
<script>
document.fonts.load('1em open_sansregular').then(function () {
const docEl = document.documentElement
docEl.className += ' open-sans-loaded'
})
</script>
<style>
.open-sans-loaded h1 {
font-family: open_sansregular;
}
</style>
当然这种方法需要考虑浏览器兼容性的问题。
相关参考
文章作者 cpselvis,原文地址 CSS @font-face 网页字体加载策略,转载请注明出处。