深入理解CSS @font-face性能优化

所属分类: 网页制作 / CSS 阅读数: 1821
收藏 0 赞 0 分享

本文主要介绍字体加载优化的常用策略,大部分内容为引用和翻译。

一、 font-face基本用法

font-face的基本用法想必大家都是知道的,基本上就是类似这样:

@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所支持的字体可以有以下类型:

src参数带不带引号都可以,参数的格式不同含义也不尽相同,比如下面:

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。

这就是font-face的最基础的用法。 接下来我们会进一步分析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");
}

很遗憾,字体并不会下载。 通常情况 下,只有当我们的页面元素用到了font-face中定义的字体的情况下,才会下载对应的字体。

注意: 这里我们说了是通常情况,这是因为,IE8在只要是定义了font-face,即使页面元素没有使用对应的字体,也会下载。

在其它浏览器中也不尽相同,

比如在 FirefoxIE 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;
}

所以总结一下,不同浏览器下载字体的策略:

  • IE8 只要定义了font-face,就会去下载字体,不论实际有没有应用该字体。
  • Firefox, IE 9+ 只有定义了font-face 并且页面有元素应用了该字体,就会去下载,不论该元素是否有文本内容。
  • Chrome, Safari 只有定义了font-face 并且页面有元素应用了该字体,并且该元素有文本内容,才会去下载字体。

那你可能会问了,如果我们的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(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即可。

五、 preload

在页面加入下面这个代码以便更快的加载字体:

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

通常和最基本的字体用法配合使用

六、 字体转 BASE64URI

这种方法就是将@font-face中定义字体时的路径直接改为字体的base64编码。

优点: 这种做法的优点是不会产生FOIT和FOUT。所以也不会有reflow和repaint. 缺点: 字体转成base64也会很大,会影响页面首次加载速度。不支持逗号分隔的形式加载多种格式的字体,只能加载一种格式字体。这导致你为了尽可能保证所有浏览器都可以兼容,通常会指定为woff格式,因为woff格式兼容性好,但是却没法使用更小体积的woff2格式,因为woff2格式兼容性差点。

七、异步加载BASE64格式URI字体

这种方法就是通过异步的方式插入带有BASE64格式URI字体的CSS链接。

八、使用Font Load API + FOUT + class切换

这种方式是期初并不使用用到@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(Flash of Faux Text)

FOFT会把字体的加载分成多个部分,首先加载罗马网络字体,然后会在加载真实的粗体和斜体的时候立即使用font-synthesis属性渲染粗体和斜体的变体。

这种方法是基于[ 使用Font Load API + FOUT + class切换 ]这种方式的,非常适合加载同一种字体但是不同粗细,字形的场景,比如罗马、粗体、斜体、粗斜体等。我们将这些字体分成2阶段: 第一阶段是罗马字体,然后立即渲染人造粗体和斜体,最后(第二阶段)用真实字体替代。这里面还可以使用sessionStorage优化访问重复视图的场景。

十、CRITICAL FOFT

CRITICAL FOFT和标准的FOFI的唯一区别就在于第一阶段罗马字体的加载,CRITICAL FOFT不会加载罗马字体的全集,只会加载它的一个子集(比如A-Za-z0-9),全集会在第二阶段加载。

十一、CRITICAL FOFT WITH DATA URI

这个和CRITICAL FOFT的唯一区别就是罗马子集字体的加载方式,前面是用Font Load API完成了,这里会将马子集字体硬编码成BASE64 URI的形式加载。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

CSS配合JavaScript做酷的动态页面效果

  利用CSS配合JavaScript的可以做很多更酷的动态页面效果,在本教程的最后给大家简单介绍一下CSS配合JS的应用。首先,要搞清楚事件和动作的概念。在客户端脚本中,JavaScript 通过对事件进行响应来获得与用户的交互。例如,当用户单击一个按钮或者在某段文字上移动鼠标
收藏 0 赞 0 分享

WEB标准,Web前端开发工程师必备技术列表

  想要打造并拥有一流的Web产品开发团队,在团队成员基础能力上一定要下功夫。对于Web前端产品开发来说,仅仅掌握Web1.0时代简单的"网页套接"是完全不够的。我结合自己的团队配备,特此罗列了Web前端产品工程师所涉及的技能列表如下:   通过许多实际项目,
收藏 0 赞 0 分享

用CSS制作Alpha滤镜测试板

alpha滤镜给制作网页特效提供了较大的创作空间,但由于它控制参数较多,在实际应用时,为了确定一组合适的参数值,不得不反复调整修改,在编辑窗口和预览窗口来回倒腾,甚是麻烦,本文介绍了一种简单的方法。制作一个“Alpha滤镜参数测试板”,在测试板上输入参数
收藏 0 赞 0 分享

非常流行的所谓的气泡窗口

普通的Alt无法自定义风格,而Sweet Titles通过JS脚本与CSS的集合.自定义了这种伪Alt风格. 前一段时间非常流行的,就所谓的气泡窗口(鼠标移到链接处出现的). 我们这里实现的用的是Sweet Titles的插件.显示效果完全由CSS控制.. 先下载Sweet Ti
收藏 0 赞 0 分享

CSS教程:li和ul标签用法举例

LI代码的格式化: A).运用CSS格式化列表符: ul li{ list-style-type:none; } B).如果你想将列表符换成图像,则: ul li{ list-style-type:none; list-style-image: url(/blog/images/
收藏 0 赞 0 分享

CSS教程:CSS中的定位(position)

  使用CSS来定位页面内层的位置,一直是比较难以掌握的事情,很多时候,往往被绝对定位的元素,总是以浏览器的左上角为坐标原点,此时,如果浏览器的大小改变,被定义的层就会偏离设计想要的位置,让人很挠头。   其实,要想控制好层的绝对定位,只要理解CSS中关于定位
收藏 0 赞 0 分享

CSS教程:盒模型(BOX Model)

  如果想熟练掌握DIV和CSS的布局方法,首先要对盒模型有足够的了解。每个HTML元素都可以看作一个装了东西的盒子,盒子里面的内容到盒子的边框之间的距离即填充(padding),盒子本身有边框(border),而盒子边框外和其他盒子之间,还有边界(margin),如图1所示。
收藏 0 赞 0 分享

无延迟翻滚的图形与CSS混合风格按钮

  在一个具有图形背景的按钮中添加CSS风格的文本,这种建立按钮的方法结合了具有CSS翻滚(CSS rollover)标记的开发速度和效率,从而有效地提高按钮外表图像的三维效果。   相比于常规的图形按钮,这些图形/CSS混合按钮可易于建立和载入,因为你只需要为空白按钮外面
收藏 0 赞 0 分享

css里expression实现界面对象的批量控制

用过css样式我们就知道, 可以定义一批对象的class属性来指定同一个样式来统一界面. 但如何统一同类型的对象的事件? 比如:界面有无数个 <img src="**.jpg"> 如何实现鼠标经过此图片, 图片的src变成是**_over.jpg?
收藏 0 赞 0 分享

CSS教程:水平对齐(text-align)

  水平对齐(text-align),用以设定元素内文本的水平对齐方式。   1.语法   text-align具体参数如下: 语法:text-align:left|right|center|justify 说明:设定元素内文本的水平对齐方式。 参数:left:左
收藏 0 赞 0 分享
查看更多