原文链接:Efficiently Rendering CSS
我承认,我不经常考虑下面这个问题:我们写的CSS如何才能有效率的
,换而言之,如何才能让浏览器更快地渲染它。
这的确是浏览器厂商应该考虑的问题:页面加载越快,人们更愿意使用它们的产品。Mozilla 有一篇关于CSS开发的最佳实践(译者注:原文链接已失效)。谷歌(尝试)改进(浏览器)让网页加载地更快。
让我们来浏览它们阐述的主要观点,然后讨论这些观点的实践性。
有一件重要的事你需要知道:浏览器从右往左解析你的CSS选择器。那意味着在下面这个例子中:
ul > li a[title='home']
第一个被解释的部分是:a[title=’home’]。第一个部分被认为是key selector
。
一共有4种选择器,它们分别是ID选择器,类选择器,标签选择器,通配符选择器
下面的选择器按照解释的速度快慢排序
#main-navigation { } /* ID (Fastest) */
body.home #page-wrap { } /* ID */
.main-navigation { } /* Class */
ul li a.current { } /* Class *
ul { } /* Tag */
ul li a { } /* Tag */
* { } /* Universal (Slowest) */
#content [title='home'] /* Universal */
当我们结合从右到左解释和关键选择器的原理,我们会发现下面这个选择器不是最有效率的。
#main-nav > li { } /* Slower than it might seem */
即使(事实)让人觉得古怪的,反直觉的……因为ID选择器是如此地有效以至于我们会认为浏览器能够快速地找到那个ID,然后快速地找到我们需要它的子节点。但是事实是:上面代码中的标签选择器被先解释。
不要这么开发CSS语言:
ul#main-navigation { }
ID是唯一的,所以不需要一个标签和ID同时存在。这么写CSS选择器让选择器效率更低。
同理适用于类选择器。尽管类选择器不是唯一的,理论上多个不同的元素可能有相同的类名。如果你想要style视元素的不同而定,你可能需要tag-qualify(标签限制),比如li.first
,但那是相当罕见的,所以一般,类选择和标签选择器不要同时使用。
David Hyatt
后代选择器是CSS中开销最大的选择器。它在标签选择器和通配符选择器就更加昂贵了。
换而言之,下面的选择器就是一个效率灾难
html body ul li a { }
我不确定,我们能否从这个原理中收获足够多。因为如果你有大量的选择器没有匹配任何元素,那是相当古怪的。但是有趣的是:在对选择器的从右到左的解释,一旦选择器匹配失败,它就停止尝试,减少了不必要的开销。
思考下面的例子:
#main-navigation li a { font-family: Georgia, Serif; }
font-family是级联的(译者注:可继承的。)所以你可能不需要这么非常具体的选择器。这个选择器是可以改进,变得更有效率:
#main-navigation { font-family: Georgia, Serif; }
David Hyatt:
一个令人悲伤的真相:如果你关心页面的效率,那么CSS3选择根本不应该被使用。
CSS3选择器,比如(:nth-child),在帮助我们定位元素,并且保持标签整洁和语义化方面,是非常棒的。但是事实是:使用这些奇妙的选择器是浏览器资源密集型的。
所以我们不应该使用它们吗?让我们考虑下实践性。
基于一个事实:十年前的计算机是比不上现在的。我感觉,这个事情(CSS选择器的效率)在那个时候是比较重要的。我感觉:我们不再经常讨论CSS选择器的效率,因为它不再是一个大的问题。
这个就是我的结论:我们上述的最佳实践不再有意义了。当然你也可以遵循这些最佳实践,因为它们没有限制你的CSS开发能力。但是你没有必要将这些实践奉为教条。如果你处于这么一个职位:你需要从边边角角挖掘站点的最后一丝性能潜力,那么值得review你的CSS代码,去看看哪里可以做得更好。如果你没有提升站点渲染速度的需求,那么不要担心CSS的效率,向前看吧。
我们知道:ID选择器是最有效率的选择器。如果你想使页面达到最高的渲染效率,你或许会想到给每个元素加上唯一的ID,然后通过ID选择器应用样式。那样,速度会更快,但也会超级可笑。这会使得代码及其非语义化,而且及其困难维护。你不会再任何基于性能的站点上看到这种方法。我认为,经验是:不要为了有效率的CSS的牺牲语义化和可维护性。