本文主要介绍字体加载优化的经常使用策略,大部份内容为引用和翻译。javascript
font-face的基本用法想必你们都是知道的,基本上就是相似这样:css
@font-face {
font-family: Lato;
src: url('font-lato/lato-regular-webfont.woff2') format('woff2'),
url('font-lato/lato-regular-webfont.woff') format('woff'),
url(font-lato/lato-regular-webfont.ttf) format("opentype");
}
p { font-family: Lato, serif; }
复制代码
这样就可使咱们的网页用上自定义字体了。 除了font-family 和 src属性以外,还拥有font-style以及font-weight属性。 src能够指定多种字体,会按顺序依次适用,好比上面的示例中会先加载woff2字体,若是失败再加载woff字体,不然加载opentype字体。 src所支持的字体能够有如下类型:html
src参数带不带引号均可以,参数的格式不一样含义也不尽相同,好比下面:java
src: url(fonts/simple.woff); /* 加载simple.woff,地址相对于样式表的地址 */
src: url(/fonts/simple.woff); /* 加载simple.woff,地址是网站的绝对地址 */
src: url(fonts/coll.otc#foo); /* 从coll.otc字符集中加载foo字体 */
src: url(fonts/coll.woff2#foo); /* 从coll.woff2字符集中加载foo字体 */
src: url(fonts.svg#simple); /* 加载id 为'simple'的SVG字体 */
复制代码
src中加载的字体地址受跨域的约束,若是想跨域加载字体,须要设置CORS。git
这就是font-face的最基础的用法。 接下来咱们会进一步分析font-face的用法,并尽量的找出优化策略。github
上面讲了字体的基本知识,那你有没有想过,字体是在何时下载的呢?当咱们仅仅在CSS中定义以下样式的时候, 页面加载,字体会自动下载吗?web
@font-face {
font-family: Lato;
src: url('font-lato/lato-regular-webfont.woff2') format('woff2'),
url('font-lato/lato-regular-webfont.woff') format('woff'),
url(font-lato/lato-regular-webfont.ttf) format("opentype");
}
复制代码
很遗憾,字体并不会下载。 一般状况下,只有当咱们的页面元素用到了font-face中定义的字体的状况下,才会下载对应的字体。c#
注意: 这里咱们说了是一般状况,这是由于,IE8在只要是定义了font-face,即便页面元素没有使用对应的字体,也会下载。跨域
在其它浏览器中也不尽相同,浏览器
好比在Firefox 和 IE 9+ 中,遇到以下状况也会下载字体:
html
<div id="test"></div>
复制代码
css
#test {
font-family: Lato;
}
复制代码
有什么特别之处呢? 你可能注意到了,这个元素虽然使用到了font-family: Lato样式,可是这个元素并无任何文本啊!!!。 按照咱们的理想状况,应该是,只有有文字内容才会去下载字体嘛。 而这就是Chrome, Safari (WebKit/Blink 等)浏览器的行为。
Chrome, Safari (WebKit/Blink 等)浏览器只有在以下相似状况才会去下载字体:
html
<div id="test">这里是有文本的哦</div>
复制代码
css
#test {
font-family: Lato;
}
复制代码
因此总结一下,不一样浏览器下载字体的策略:
那你可能会问了,若是咱们的DOM元素是经过动态插入的呢?好比:
var el = document.createElement('div');
el.style.fontFamily = 'open_sansregular';
document.body.appendChild(el);
el.innerHTML = 'Content.';
复制代码
答案是同样的,它的下载策略以下:
var el = document.createElement('div');
el.style.fontFamily = 'open_sansregular';
/* 到这里,IE8就会开始下载字体 */
document.body.appendChild(el);
/* 只有到这里,Firefox, IE 9+ 才会开始下载字体 */
el.innerHTML = 'Content.';
/* 只有到这里,Chrome, Safari 才会开始下载字体 */
复制代码
FOIT是浏览器在加载字体的时候的默认表现形式,也就是在字体加载过程当中,页面是看不到文本内容的。在现代浏览器中,FOIT会致使这种现象出现至多3秒。FOIT会致使不好的用户体验,这是咱们须要尽可能去避免的。
FOUT意思是在字体加载过程当中使用默认的系统字体,字体加载完后显示加载的字体,若是超过了FOIT(3s)字体还没加载,则继续使用默认的系统字体。
IE浏览器和Edge不会等待FOIT超时才显示默认字体,会当即显示默认字体。FOUT比FOIT好,可是须要注意它引发的reflow.
那么要想使浏览器有FOUT行为,咱们须要在设置@font-face的时候给它加一个属性:font-display。 font-display默认是auto, 可选属性与含义以下:
通常设置成fallback和optional便可。
在页面加入下面这个代码以便更快的加载字体:
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
复制代码
一般和最基本的字体用法配合使用
这种方法就是将@font-face中定义字体时的路径直接改成字体的base64编码。
优势: 这种作法的优势是不会产生FOIT和FOUT。因此也不会有reflow和repaint. 缺点: 字体转成base64也会很大,会影响页面首次加载速度。不支持逗号分隔的形式加载多种格式的字体,只能加载一种格式字体。这致使你为了尽量保证全部浏览器均可以兼容,一般会指定为woff格式,由于woff格式兼容性好,可是却无法使用更小体积的woff2格式,由于woff2格式兼容性差点。
这种方法就是经过异步的方式插入带有BASE64格式URI字体的CSS连接。
这种方式是期初并不使用用到@font-face的class,而后用Font Load API加载咱们想用的字体,而后切换相应的CSS便可。Font Load API是原生的API:
document.fonts.load('1em open_sansregular')
.then(function() {
var docEl = document.documentElement;
docEl.className += ' open-sans-loaded';
});
.open-sans-loaded h1 {
font-family: open_sansregular;
}
复制代码
固然这种方法须要考虑浏览器兼容性的问题。
FOFT会把字体的加载分红多个部分,首先加载罗马网络字体,而后会在加载真实的粗体和斜体的时候当即使用font-synthesis属性渲染粗体和斜体的变体。
这种方法是基于[使用Font Load API + FOUT + class切换
]这种方式的,很是适合加载同一种字体可是不一样粗细,字形的场景,好比罗马、粗体、斜体、粗斜体等。咱们将这些字体分红2阶段: 第一阶段是罗马字体,而后当即渲染人造粗体和斜体,最后(第二阶段)用真实字体替代。这里面还可使用sessionStorage优化访问重复视图的场景。
CRITICAL FOFT和标准的FOFI的惟一区别就在于第一阶段罗马字体的加载,CRITICAL FOFT不会加载罗马字体的全集,只会加载它的一个子集(好比A-Za-z0-9),全集会在第二阶段加载。
这个和CRITICAL FOFT的惟一区别就是罗马子集字体的加载方式,前面是用Font Load API完成了,这里会将马子集字体硬编码成BASE64 URI的形式加载。
这个同上面的惟一区别仍是第一阶段罗马子集字体的加载方式,它采用的是preload的形式加载。
总的字体加载的策略能够用这个图总结以下:
本文主要翻译自以下博客文章
《IVWEB 技术周刊》 震撼上线了,关注公众号:IVWEB社区,每周定时推送优质文章。