在High Performance Web Sites第5章, 我简单地提及了@import 对页面性能有负面影响。现在我通过创建几个测试页面及其HTTP瀑布图来更深入的阐述在Web 2.0 Expo中的观点。总而言之,如果你要更快的并行下载样式表,使 用LINK替代 @import
LINK 对 @import
页面包含样式表有2种方式. 你可以使用LINK标记:
<link rel='stylesheet' href='a.css'>
或者你可以使用@import规则:
<style> @import url('a.css'); </style>
我建议使用LINK—你必须将@import放在样式的顶部否则它不会生效,而且事实证明避免@import对性能也有好处.
@import @import
我将通过不同的方法验证LINK和@import的影响, 在下面例子中,有2个样式表: a.css 和b.css 。每个样式表均被配置为下载时间为2秒,以便直观的感受性 能影响。第1个例子使用@import来引入样式表。这个例子称为@import @import, HTML文档包含以下样式:
<style> @import url('a.css'); @import url('b.css'); </style>
如果你想一直以这种方式使用@import, 那么没有性能问题,虽然我们将在下面提到由于条件竞争会导致JavaScript错误. 通过图1可以看到,这2个样式表确 实是以并行方式下载 (第一个短请求是HTML文档),只有当@import嵌入其它样式表或和LINK结合使用时才会导致问题发生.
LINK @import
例子LINK @import使用 LINK 引入 a.css, 使用 @import 引入 b.css:
<link rel='stylesheet' type='text/css' href='a.css'> <style> @import url('b.css'); </style>
在IE中 (6, 7, 8均已测试), 这会导致顺序下载样式表, 见图2. 并行下载是构建快速页面的关键。和展示的一样,IE的这个行为导致了页面要使用更长的时 间来完成。
LINK with @import
在 LINK with @import 例子中, 使用LINK引入a.css,在 a.css 中使用 @import 来加载 b.css:
<link rel='stylesheet' type='text/css' href='a.css'>
@import url('b.css');
这种方式也会阻止脚本并行加载, 不同的是这会发生在所有浏览器上. 当我们思考为什么会发生这样的情况时, 请不要惊讶。浏览器下载并解析a.css,当浏 览器在文件开头看到@import后会首先加载b.css.
LINK blocks @import
在IE中对上面的例子进行简单的改变会造成令人吃惊的结果: 使用LINK引入a.css,然后新引入一个称为proxy.css的样式表. proxy.css 被配置为立即返回 ,并且它通过@import引入b.css.
<link rel='stylesheet' type='text/css' href='a.css'> <link rel='stylesheet' type='text/css' href='proxy.css'>
@import url('b.css');
这个例子在IE中的执行结果, LINK blocks @import, 见图4. 第一个 请求是HTML文档,第2个请求是a.css (2秒). 第3个(很短的)请求是proxy.css. 第4个请求是b.css (2秒). 令人惊奇的是,IE 在a.css完成之前不会下载b.css. 在所有其它的浏览器中, 这个阻止的问题不会出现,会更快的下载,见图5.
many @imports
例子many @imports演示了在IE中使用@import会导致和预期不一致的下载顺 序。这个例子有6个样式表(每个耗时2秒) 和1个脚本(耗时4秒).
<style> @import url('a.css'); @import url('b.css'); @import url('c.css'); @import url('d.css'); @import url('e.css'); @import url('f.css'); </style> <script src='one.js' type='text/javascript'></script>
图6中, 耗时最长的是4秒的脚本. 虽然它在代码中是最后引用的,但是在IE中它是最先下载的。如果脚本中包含依赖样式表的代码(例如 getElementsByClassName),就会发生不可预料的结果,这是因为虽然开发人员把脚本放在最后面,但是脚本先于样式表加载产生的。
LINK LINK
在样式表中使用LINK是易用且安全的:
<link rel='stylesheet' type='text/css' href='a.css'> <link rel='stylesheet' type='text/css' href='b.css'>
使用LINK可以确保样式表在所有浏览器中是并行下载的. 例子 LINK LINK 演示 了这种情况, 见图7. 使用LINK还能确保下载顺序是按照开发人员指定的顺序下载的.
IE应该解决上面这些问题,尤其糟糕的是下载顺序是混乱的,所有的浏览器都应该在下载样式表时实现一个小的文件扫描,解析@import并且马上下载这些文 件 。但在浏览器改变之前,我建议使用LINK来替代@import来引入样式表.
更新: 2009年4月10日下午1:07
基于评论里面的问题, 我增加了2个测试: LINK with @imports 和 Many LINKs. 每个例子的HTML文档里面插入了4个样式表。LINK with @imports 使用LINK加载proxy.css; proxy.css 使用@import加载4 个样式表. Many LINKs 使用4个LINK标记加载样式表(我建议的做法). 图8和图9展 示了对应的HTTP瀑布图
查看LINK with @imports, 第一个问题是4个样式表不会在proxy.css下 载完之前开始下载. 这种情况发生在所有浏览器上. 相反, Many LINKs 马上开始 下载样式表.
第2个问题是IE改变了下载顺序. 我在每个页面的底端增加了一个耗时10秒的脚本(很长的柱装图). 在所有浏览器中,和指定的顺序一样,@import 样式表 (proxy.css文件中的) 最先下载,脚本最后下载. 然而在IE中,脚本先于@import样式表加载, 见LINK with @imports图8. 由于在IE6和7中只能有2个并发连接,这会导致在脚本结束之前样式表会耗费更长的时间.既然IE在所有样式 表加载之前不会渲染页面内任何的元素,使用@import会导致页面空白12秒. 使用LINK替代@import维持了原有顺序, 见Many LINKs 图9. 因此, 页面会在4秒内渲染完毕.
这些资源的加载时间被人为增大到了足以看到以上的现象。但对于慢速上网的用户尤其是世界上的新兴市场,这个时间不一定和实际相差很多。重点:
- 在样式表中使用 @import 会增加一倍或几倍的页面下载时间.
- 在IE中使用 @import 会导致加载顺序被更改.这可能会导致样式表下载很长时间进而阻塞页面渲染给人感觉页面加载很慢.