一尘不染

选择器引擎准确地向哪个方向读取?

css

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

div.name

快于:

.name

但是,我最近读到,大多数CSS选择器引擎都是从右向左读取的,在这种情况下,第一个示例实际上不会更慢吗?因为选择器引擎会简单地找到具有类名称的每个元素,然后必须识别出哪个是divs?

CSS选择器引擎通常阅读哪种方式?从左到右还是从右到左?而且,如果他们通常从右到左阅读,是否有人可以向我解释原因(我看不到从选择器引擎的角度来从右向左阅读有何意义)?


阅读 269

收藏
2020-05-16

共1个答案

一尘不染

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

大致了解CSS选择器引擎的哪种方式?从左到右还是从右到左?而且,如果他们通常从右到左阅读,是否有人可以向我解释原因(我看不到从选择器引擎的角度来从右向左阅读有何意义)?

坦白地说,要确定哪个选择器在给定浏览器中变慢几乎是不可能的,跨浏览器则要少得多。性能趋于波动且不可预测,尤其是在这种微观规模和不可预测的文档结构下。即使我们讨论理论性能,它最终也取决于实现。

话虽如此,正如BorisZbarsky对另一个问题的回答和Guffa对您的问题的回答所示,典型的浏览器(当前在所有主要的布局引擎中都是如此)采用一个元素,并评估所有候选选择器以查看其匹配的选择器,而不是查找与给定选择器匹配的一组元素。这是一个微妙但非常重要的区别。鲍里斯(Boris)提供的技术说明不仅详尽到令人难以置信,而且权威性强(在他使用Firefox使用的引擎Gecko的过程中),因此,我强烈建议您阅读它。

但是我认为我应该解决您的问题中似乎还有另一个问题:

因为选择器引擎会简单地找到具有类名称的每个元素,然后必须识别出哪个是divs?

链接的问题解释了为什么选择器通常是从右到左#foo ul.round.fancy li.current读取的li.current, ul.round.fancy, #foo,因此也是read ,但实际上在每个元素(`.current, li, .fancy, .round, ul,

foo`)中是从右到左读取的吗?应该是吗

我从未实现CSS,也从未见过其他浏览器如何实现CSS。从上面链接的答案中我们确实知道,浏览器使用从右到左匹配来遍历选择器内的组合器,例如>本示例中的组合器:

section > div.second > div.third

如果一个元素不是a div.third,则没有检查它的父对象是否是div.second其父对象是a的点section

但是,我不认为这种从右到左的顺序会一直向下钻到简单的选择器级别。换句话说,我并不认为浏览器使用从右到左评价的简单选择器序列(也被称为化合物选择器)的每个部分的右至左的评价内跨越
一系列 化合物的选择器由分离组合器。

例如,考虑以下人为设计和高度夸大的选择器:

div.name[data-foo="bar"]:nth-child(5):hover::after

现在,谁也不能保证一个浏览器 一定是 检查这些条件,按以下顺序的元素:

  1. 指针是否位于此元素上?
  2. 此元素是其父项的第五个孩子吗?
  3. 此元素是否具有data-foo带有值的属性bar
  4. 这个元素有一个name类吗?
  5. 这是div元素吗?

也不将这个选择器,它是 功能上相同 于上述除以其简单选择错杂各处, 不一定 按照下列顺序进行评估:

div:hover[data-foo="bar"].name:nth-child(5)::after
  1. 此元素是其父项的第五个孩子吗?
  2. 这个元素有一个name类吗?
  3. 此元素是否具有data-foo带有值的属性bar
  4. 指针是否位于此元素上?
  5. 这是div元素吗?

完全没有理由出于性能原因而强制执行此类命令。实际上,我认为通过优先选择某些简单选择器(无论它们在序列中的什么位置),可以提高性能。(您还将注意到,::after没有考虑到-
这是因为伪元素不是简单的选择器,甚至从不输入匹配方程式。)

例如,众所周知,ID选择器是最快的。好吧,鲍里斯(Boris)在对链接问题的回答的最后一段中这样说:

还要注意,浏览器已经做过其他优化,甚至可以避免匹配绝对不匹配的规则。例如,如果最右边的选择器具有一个ID,并且该ID与元素的ID不匹配,则在壁虎中根本不会尝试将该选择器与该元素进行匹配:尝试的“具有ID的选择器”集合来自对元素ID的哈希表查找。因此,仅考虑最右边选择器的标记/类/
ID,这就是70%的规则很有可能匹配, 但仍然 不匹配。

换句话说,是否具有如下所示的选择器:

div#foo.bar:first-child

或这个:

div.bar:first-child#foo

壁虎将 始终 先检查ID和类,而不管其在序列中的位置。如果该元素没有ID和与选择器匹配的类,则会立即将其丢弃。如果你问我,很快就可以了。

那只是壁虎为例。这在实现之间也可能有所不同(例如,Gecko和WebKit可能与Trident甚至Presto有所不同)。当然,有一些供应商普遍同意的策略和方法(首先检查ID可能没有区别),但细节上可能有所不同。

2020-05-16