在浏览器加载CSS 时防止影响页面渲染的方法

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

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

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


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

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

CSS Code复制内容到剪贴板
  1. <link rel="stylesheet" href="css.css" media="none">  

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

CSS Code复制内容到剪贴板
  1. <link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">  


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

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

CSS Code复制内容到剪贴板
  1. <link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">   
  2. <noscript><link rel="stylesheet" href="css.css"></noscript>  

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

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

CSS Code复制内容到剪贴板
  1. <link rel="stylesheet" href="main.css">   
  2. <link rel="stylesheet" href="font.css" media="none" onload="if(media!='all')media='all'">  

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

CSS Code复制内容到剪贴板
  1. @font-face {   
  2.   font-family: Merriweather;   
  3.   font-stylenormal;   
  4.   font-weight: 400;   
  5.   srclocal('Merriweather'), url('data:application/x-font-woff;charset=utf-8;base64,...')   
  6. }  

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

CSS Code复制内容到剪贴板
  1. body {   
  2.   font-family: Merriweather, "Lucida Grande", ...;   
  3. }  

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

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

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

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

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


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

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

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

总结

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

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

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

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 分享
查看更多