加载 CSS 时不影响页面渲染 已翻译 100%

oschina 投递于 2015/04/03 01:37 (共 7 段, 翻译完成于 04-03)
阅读 6428
收藏 161
CSS
3
加载中

本文展示了一种技术,它能通过异步下载样式表,以阻止它们的下载阻塞页面的渲染,从而尽可能快的让访问者获取到信息内容。

警告! 我发这篇帖子全是好意,但是它并不负责让读它的人意识到下面将会遇到的问题. 社区很快地给了我许多的反馈 (有些反馈我很感激) ,而越来越明显的是这项技术并不如我所希望的那样稳定. 不像我那样的成功地对它进行了测试和利用,许多开发者在 IE 和 Firefox 中都遇到了问题( F F测试版中直接崩溃) 而其他人则报告在 Chrome 和 Safari 中是成功的。我现在的建议是: 不要将其用于产品。我计划处理好这些反馈,并结合任何有关的信息对本文进行更新。

LeoXu
LeoXu
翻译于 2015/04/03 13:40
1

这些技术背后的原理不是新的。例如灯丝(Filament)技术组已经发布了大量有关 加载CSS 和字体的内容. 我写就本文以记录我对加载非阻塞资源的想法和观点。

触发异步样式下载的诀窍是使用一个 <link> 元素,并 为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'">
LeoXu
LeoXu
翻译于 2015/04/03 13:50
1

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

这一技术使用了 JavaScript,但是你也可以在一个<noscript>元素中封装一个等价的阻塞方式的 <link> 元素来处理不能运行 JavaScript 的浏览器:

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

这项技术有一个副作用。当一个非阻塞的样式表完成加载,文档就将进行重绘,以反映它定义的任何新的样式规则。而注入新的样式到页面中会触发内容回流, 但这也只是在这对第一次没有历史缓存的页面加载过程中会是一个问题。由于任何跟性能有关的东西,你都将要在需要控制一次回流耗费超过潜在的速度优势时,进行必要的调整。

LeoXu
LeoXu
翻译于 2015/04/03 14:03
1

使用非阻塞 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 就会被使用. 我尝试去确保回退的字体将相似的布局特征共享给优先选择的字体,那样不可避免的回流就尽可能微妙了。

LeoXu
LeoXu
翻译于 2015/04/03 14:13
1

我在基于一个模拟的 3G 网络连接的 Chrome 中,使用我的 Google Analytics Debugger 站点 拿阻塞和非阻塞方式进行了对比测试。本地的测试产生了如下所示的网络图;注意 DOMContentLoaded 在更早的 450ms 触发了,而资源在运用了非阻塞技术后下载起来更快了:

模拟 3G 网络的图形。顶部显示了阻塞式的字体。底部显示了非阻塞式的字体。

将其部署到一个测试服务器并在 3G 连接环境下运行 webpagetest 构造产生了如下时间线 :

3G 时间线。顶部显示阻塞式的字体,底部展示非阻塞式的字体。

LeoXu
LeoXu
翻译于 2015/04/03 14:21
1

两种方法都花了2.8秒钟来完整的渲染页面,但是非阻塞方法比一般的阻塞方法使得绘制早了1秒钟。在在主样式表进行了内联的情况下运行相同的测试,显示了在将非阻塞 CSS 被应用于处理字体时有0.7秒的时间优势:

主 CSS 内容的 3G 时间线。顶部显示阻塞式字体,底部显示非阻塞式字体。

这一技术对于字体的效果确实很好,但是我也建议对新的 CSS 字体加载模块保持密切关注,它会给与我们超过字体加载的更多的控制能力。

LeoXu
LeoXu
翻译于 2015/04/03 14:29
1

总结

加载字体是应用非阻塞技术的一个例子,而他也可以被用于其它的目的,比如从核心的 CSS 处分离出 JavaScript 增强的样式。

我已经开始去尝试将样式分成框架(核心布局) 和展现 (其它所有的东西)这种想法,它可以让重要的页面布局阻塞页面渲染,而可见的样式数据延迟一会。

LeoXu
LeoXu
翻译于 2015/04/03 14:34
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(13)

灰灰
灰灰
以为只有JS才考虑非阻塞,居然连CSS都可以,太牛了。
shijunti
shijunti
我觉得还得浏览器支持,把css做成js样的
tinshen
tinshen
浏览器支持的怎么样是关键.
喵星人123
喵星人123
把样式表放在末尾 是不是首先会展示出没有样式的HTML结构
yale8848
yale8848
不能用于产品的技术都是耍流氓!
昊翔
昊翔

引用来自“错觉”的评论

页面样式都不对 请问这么早给他看 出于什么目的

引用来自“捏造的信仰”的评论

对字体加载来说非常实用
点击此处输入评论
MJ_PC_Lab
MJ_PC_Lab
非阻塞会导致浏览器重绘,可能很费电
KenSun
KenSun
这非阻塞非阻塞听得真别扭
FOG_Y
FOG_Y
总有适用情况的,难怪很多时候发现明明载入完成了,连接点不了。。。
edielei
edielei
歪门邪道的技术不要学!
返回顶部
顶部