CSS Selector Performance has changed! (For the better)

来源:互联网 发布:linux 获取svn版本号 编辑:程序博客网 时间:2024/05/16 06:18

可能有些人看过MDN上面 Writing efficient CSS (作者:David Hyatt)这篇文章,不过网站也标注了,这是2000年写的,建议参考一下本文所翻译的文章(2011年12月29日,作者:Nicole Sullivan)关于CSS选择器优化。

本文地址:点击打开链接

像David Hyatt的书写高效CSS等优秀的文章,帮助开发者适应了一个基本的选择器匹配大背景。我们从Steve Souders(还有其他人)知道选择器从右向左匹配,以及一些选择器非常难匹配,最好避免使用。比如,我们被告诉说后代选择器是慢的,尤其是当最右的选择器匹配了页面上许多元素。所有这些都是极好的信息,在我们还什么都没有的时候,但是正如目前的情况,时代改变了。感谢Antti Koivisto的一些令人赞叹的工作,有许多选择器我们不再需要担心了。

Antti为Webkit核贡献代码,他最近花了一些时间优化CSS选择器匹配。事实上,在他完成了他的工作以后,他说:“我的观点是作者们不应该再需要担心优化选择器(从我所看到的,他们通常不需要),(优化选择器)应该是(浏览器)引擎的工作。”

那听起来妙极了!我喜欢能够以一种使得我的结构更有意义的方式使用选择器,然后让渲染引擎来处理选择器优化。所以,他做了什么?不只是一件事,他创造了多层次的优化——我们将要特别地看一下四种优化:

1. Style Sharing

2. Rule Hashes

3. Ancestor Filters

4. Fast Path


Style Sharing

样式分享允许浏览器去算出在样式树上的一个元素拥有相同的样式,正如它已经算出的一些东西。为什么要做两次相同的运算呢?比如:

<div>  <p>foo</p>  <p>bar</p></div>
如果浏览器引擎已经为第一个段落 <p> 计算出了样式,那它不需要再为第二个计算样式了。这一种简单但聪明的改变节省了浏览器很多的工作。


Rule Hashes

直到目前,我们都知道浏览器从右向左匹配样式,所以最右的选择器非常重要。Rule Hashes把一个样式表基于最优选择器进行分组。比如以下样式表将被分成三组:

a {}div p {}div p.legal {}#sidebar a {}#sidebar p {}
app.legala {}div p {}div p.legal {}#sidebar a {}#sidebar p {} 当浏览器使用rule hashes时,它不必在整个样式表中查看每一个单独的选择器,而是在一个实际上有可能找到匹配的更小的选择器分组里。这是另一个简单但是非常聪明的改变,剔除了对页面上每一个单独的HTML元素不必要的工作。


Ancestor Filters

祖先过滤器有一些复杂。他们是 Probability filters 概率过滤器,计算一个选择器将会匹配的可能性。基于这个原因,当涉及的元素不含被要求的匹配的祖先时,祖先选择器可以快速剔除样式规则。在这种情况,它对后代选择器孩子选择器以及基于class、id和tag的匹配进行测试。特别地,后代选择器之前被认为是很慢的,因为渲染引擎需要在每一个祖先节点进行循环测试一个匹配。Bloom filter 来援救这个问题。

一个 bloom 过滤器是一种数据结构,让你测试一个特别的选择器是否是一个集合的成员。听起来很像选择器匹配,是吧?Bloom 过滤器测试一个CSS规则,是否是匹配了你当前正在测试的元素的样式规则的集合的成员。关于这个过滤器很棒的一件事是假的positive是有可能的,而假的negative不是。这意味着如果过滤器说一个选择器不匹配当前元素,浏览器可以停止查看并跳到下一个选择器。节省了巨大的时间!另一方面,如果过滤器说当前的选择器匹配,浏览器可以使用常规的匹配方法继续查看,以100%确定它确实是一个匹配。大的样式表将有更多的false positive,所以保持你的样式表合理的“消瘦”是一个好主意

The ancestor filter makes matchingdescendant and child selectors very fast. 祖先过滤器做后代和孩子选择器匹配非常快。它也可以用来把一些慢的选择器划分成小的子树,然后浏览器只需要极少地处理不太高效的选择器。


Fast Path

快速路径使用一种非递归,完全内联的循环,重新执行更常见的匹配逻辑。它用于匹配含有以下任何一种组合的选择器:

1. 后代、孩子、和子选择器组合

2. tag、id、class和属性选择器

快速路径跨越如此大的组合器和选择器的子集提高了表现。事实上,他们见证了25%的整体提高 with a 2X improvement for descendant and child selectors (不确定怎么翻译)。此外,除了样式匹配,这个已经被用在 querySelectorAll。


如果这么多东西都没提高了,还有什么是仍然慢的呢?

What is still slow?

根据Antti,直接或间接跟随(同胞)组合器仍然是慢的,但是祖先过滤器和rule hashes可以降低这些选择器的影响,因为这些选择器将只被很少地匹配。他还说,对于webkit仍然有很多余地去优化假类和假元素,但是尽管如此,他们(pseudo classes and elements)比试图使用JavaScript和DOM操作,来做相同的事情快得多。事实上,仍然有提升到空间。他说:“从样式匹配角度来说,适度地多使用一切将表现的刚刚好。”

我喜欢听到这个。总结就是如果我们保持样式表大小是明智的,合理使用我们的选择器,我们就不需要控制我们自己去匹配昨天的浏览器图景


0 0
原创粉丝点击