我一直相信(尽管我现在怀疑这些信念的有效性):
div.name
快于:
.name
但是我最近读过大多数CSS选择器引擎从右到左阅读,在这种情况下第一个例子实际上不会更慢?因为选择器引擎会简单地找到每个具有一个名称类的元素,然后必须确定哪些是div
s?
CSS选择器引擎通常以哪种方式读取?从左到右还是从右到左?如果他们一般从右到左阅读,有人可以请我解释一下为什么(我看不出从选择引擎的右向左阅读是否有意义?)
答案 0 :(得分:11)
但是我最近读过大多数CSS选择器引擎从右到左阅读,在这种情况下第一个例子实际上不会更慢?
CSS选择器引擎通常读取哪种方式?从左到右还是从右到左?如果他们一般从右到左阅读,有人可以请我解释一下为什么(我无法看到从选择引擎的右侧向右阅读是否合理)?
坦率地说,在给定的浏览器中,几乎不可能分辨哪个选择器会慢一些,而不是浏览器。性能往往波动并且不可预测,尤其是在这种微观尺度和不可预测的文档结构上。即使我们谈论理论表现,它最终还是取决于实施。
如上所述,如Boris Zbarsky's answer to this other question和Guffa's answer to yours中所示,典型的浏览器(目前所有主要布局引擎都是如此)接受一个元素并评估所有候选选择器以查看哪些它匹配,而不是找到一组匹配给定选择器的元素。这是一个微妙但非常重要的区别。 Boris提供的技术解释不仅非常详细,而且具有权威性(因为他使用的是Firefox使用的引擎Gecko),因此我强烈建议您阅读它。
但我认为我应该解决你问题中另一个问题:
由于选择器引擎只是找到一个名称类的每个元素,然后必须确定哪些是
div
s?
以及Patrick McElhaney's comment:
链接的问题解释了为什么选择器一般从右向左阅读,因此
#foo ul.round.fancy li.current
被读取li.current, ul.round.fancy, #foo
,但它在每个元素中都是从右向左读取的{{1 }})?应该是吗?
我从未实现过CSS,也没有看到其他浏览器如何实现它。我们从上面链接的答案中知道,浏览器使用从右到左的匹配来遍历选择器中的组合器,例如本示例中的.current, li, .fancy, .round, ul, #foo
组合器:
>
如果某个元素不是section > div.second > div.third
,则无法检查其父级是div.third
,其父级是div.second
。
但是,我不相信这种从右到左的顺序一直向下钻到简单的选择器级别。换句话说,我不相信浏览器在系列的从右到左评估中对简单选择器序列(也称为复合选择器)的每个部分使用从右到左的评估由组合子分离的化合物选择器。
例如,考虑一下这个人为的,高度夸张的选择器:
section
现在,无法保证浏览器必须按以下顺序检查元素的这些条件:
div.name[data-foo="bar"]:nth-child(5):hover::after
属性值是否为data-foo
?bar
类?name
元素吗?这个选择器功能相同上面的选择器除了简单的选择器混乱之外,必然按以下顺序进行评估:
div
div:hover[data-foo="bar"].name:nth-child(5)::after
类?name
属性值是否为data-foo
?bar
元素吗?由于性能原因,没有理由强制执行此类命令。实际上,我认为首先选择某些类型的简单选择器可以提高性能,无论它们在序列中的哪个位置。 (你还会注意到div
没有被考虑 - 因为伪元素不是简单的选择器,甚至不会进入匹配方程。)
例如,众所周知,ID选择器是最快的。好吧,鲍里斯在他对相关问题的回答的最后一段中说了这一点:
另请注意,浏览器已经进行了其他优化,以避免尝试匹配绝对不匹配的规则。例如,如果最右边的选择器有一个id并且该id与元素的id不匹配,那么在Gecko中根本不会尝试将该选择器与该元素匹配:&#set 34; ID为#34的选择器;尝试来自对元素ID的哈希表查找。因此,在考虑最右边的选择器的标签/类/ id之后,这是70%的匹配仍然不匹配的规则。
换句话说,你是否有一个看起来像这样的选择器:
::after
或者这个:
div#foo.bar:first-child
Gecko将始终始终检查ID和类,无论它在序列中的位置如何。如果元素没有ID和与选择器匹配的类,则它立即被丢弃。如果你问我,那就太快了。
这只是Gecko的一个例子。这在实现之间也可能不同(例如,Gecko和WebKit可能与Trident或甚至Presto不同)。当然,供应商普遍同意的策略和方法(首先检查ID可能不同),但细节可能不同。
答案 1 :(得分:6)
选择器引擎不查找应用规则的元素,它查找适用于特定元素的规则。因此,从右到左阅读选择器是有意义的。
这样的选择器:
div span.text a.demo
会使选择器引擎执行这些检查以查看选择器是否适用于元素:
a
类,是demo
?span
的{{1}}元素的祖先?text
元素的祖先?