实现CSS异步加载,不影响页面渲染

前言

触发异步样式下载的诀窍是使用一个 元素,并 为media 属性设置一个不可用的值 (我用的是 media=”none”, 不过其它的任何值也是可以的)。当一个媒体查询的结果值计算出来是 false 的时候,浏览器仍然会下载样式表,但是不会在渲染页面之前等待样式表的资源可用。


<link rel="stylesheet" href="css.css" media="none">

样式表一下载好,media 属性就必须被设置一个可用的值,以便样式规则能被应用到 html 文档中onload 事件就可以用来将 media 属性切换到all:


<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">

这种加载 CSS 的方法将比标准的方法在向访问者传送有用信息的速度上快很多。至关重要的 CSS 加载时仍然可以用一般的阻塞方式处理 (或者你也可以为了最终的性能对它进行内联处理) ,而不重要的样式则可以慢慢下载,并在解析/渲染过程的后面一点的阶段进行应用。

实战:使用非阻塞 CSS 加载字体

字体第一次绘制的性能是一个问题,它们是阻塞式的资源,也会让应用它们的文本在该字体下载时不可见 。使用上述示例中的非阻塞链接,就可能在幕后下载包含字体数据的样式表,不阻塞压面的渲染:


<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="font.css" media="none" onload="if(media!='all')media='all'">

font.css 包含一个 base64 编码的 WOFF 版本的 Merriweather 字体。


@font-face {
  font-family: Merriweather;
  font-style: normal;
  font-weight: 400;
  src: local('Merriweather'), url('data:application/x-font-woff;charset=utf-8;base64,...')
}

main.css 包含了需要应用到站点的所有样式规则。下面是字体的声明:


body {
  font-family: Merriweather, "Lucida Grande", ...;
}

当字体正在下载时,第一个匹配到的备用回退字体 (这里就是 Lucida Grande) 被用来渲染页面的内容。 一旦字体样式表被应用了,Merriweather 就会被使用. 我尝试去确保回退的字体将相似的布局特征共享给优先选择的字体,那样不可避免的回流就尽可能微妙了。