选择器引擎在哪个方向读取?

时间:2012-04-11 12:57:04

标签: css css-selectors

我一直相信(尽管我现在怀疑这些信念的有效性):

div.name

快于:

.name

但是我最近读过大多数CSS选择器引擎从右到左阅读,在这种情况下第一个例子实际上不会更慢?因为选择器引擎会简单地找到每个具有一个名称类的元素,然后必须确定哪些是div s?

CSS选择器引擎通常以哪种方式读取?从左到右还是从右到左?如果他们一般从右到左阅读,有人可以请我解释一下为什么(我看不出从选择引擎的右向左阅读是否有意义?)

2 个答案:

答案 0 :(得分:11)

  

但是我最近读过大多数CSS选择器引擎从右到左阅读,在这种情况下第一个例子实际上不会更慢?

     

CSS选择器引擎通常读取哪种方式?从左到右还是从右到左?如果他们一般从右到左阅读,有人可以请我解释一下为什么(我无法看到从选择引擎的右侧向右阅读是否合理)?

坦率地说,在给定的浏览器中,几乎不可能分辨哪个选择器会慢一些,而不是浏览器。性能往往波动并且不可预测,尤其是在这种微观尺度和不可预测的文档结构上。即使我们谈论理论表现,它最终还是取决于实施。

如上所述,如Boris Zbarsky's answer to this other questionGuffa'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

现在,无法保证浏览器必须按以下顺序检查元素的这些条件:

  1. 指针是否在此元素上?
  2. 此元素是其父元素的第5个子元素吗?
  3. 此元素的div.name[data-foo="bar"]:nth-child(5):hover::after 属性值是否为data-foo
  4. 此元素是否有bar类?
  5. 这是name元素吗?
  6. 这个选择器功能相同上面的选择器除了简单的选择器混乱之外,必然按以下顺序进行评估:

    div
    1. 此元素是其父元素的第5个子元素吗?
    2. 此元素是否有div:hover[data-foo="bar"].name:nth-child(5)::after 类?
    3. 此元素的name属性值是否为data-foo
    4. 指针是否在此元素上?
    5. 这是bar元素吗?
    6. 由于性能原因,没有理由强制执行此类命令。实际上,我认为首先选择某些类型的简单选择器可以提高性能,无论它们在序列中的哪个位置。 (你还会注意到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元素的祖先?