关于html:为什么浏览器从右到左匹配CSS选择器?

Why do browsers match CSS selectors from right to left?

CSS选择器由浏览器引擎从右到左匹配。因此,他们首先找到孩子,然后检查他们的父母,看看他们是否符合规则的其余部分。

  • 为什么是这样?
  • 是因为规范说的吗?
  • 如果从左到右进行评估,它是否会影响最终布局?
  • 对我来说,最简单的方法是使用元素数量最少的选择器。首先是ID(因为它们应该只返回1个元素)。然后可能是类或具有最少节点数的元素 - 例如页面上可能只有一个跨度,因此可以使用引用跨度的任何规则直接转到该节点。

    以下是备份我的说法的一些链接

  • http://code.google.com/speed/page-speed/docs/rendering.html
  • https://developer.mozilla.org/en/Writing_Efficient_CSS
  • 这听起来像这样做是为了避免必须看到父母的所有孩子(可能是很多孩子),而不是一个孩子的所有父母必须是一个孩子。即使DOM很深,它也只会在每个级别查看一个节点而不是RTL匹配中的多个节点。评估CSS选择器LTR或RTL更容易/更快?


    请记住,当浏览器正在进行选择器匹配时,它有一个元素(它试图确定样式的元素)以及所有规则及其选择器,它需要找到与元素匹配的规则。这与通常的jQuery不同,比如,你只有一个选择器,你需要找到与该选择器匹配的所有元素。

    如果您只有一个选择器并且只有一个元素可以与该选择器进行比较,那么在某些情况下从左到右更有意义。但这绝不是浏览器的情况。浏览器正在尝试呈现Gmail或其他任何内容,并且有一个它??正在尝试设置样式,以及Gmail放入其样式表中的10,000多个规则(我没有提供该数字)。

    特别是,在这种情况下,浏览器正在查看它所考虑的大多数选择器与所讨论的元素不匹配。所以问题就变成了决定选择器不尽可能快的问题;如果在匹配的情况下需要一些额外的工作,由于您在不匹配的情况下保存的所有工作,您仍然会赢。

    如果你只是将选择器的最右边部分与你的元素相匹配,那么它很可能无法匹配而且你已经完成了。如果它匹配,你必须做更多的工作,但只与你的树深度成比例,这在大多数情况下并不是那么大。

    另一方面,如果你从匹配选择器的最左边部分开始......你对它有什么匹配?您必须开始遍历DOM,寻找可能与之匹配的节点。只是发现最左边的部分没有任何匹配可能需要一段时间。

    所以浏览器从右边匹配;它提供了一个明显的起点,让您可以非常快速地摆脱大多数候选选择器。你可以在http://groups.google.com/group/mozilla.dev.tech.layout/browse_thread/thread/b185e455a0b3562a/7db34de545c17665上看到一些数据(虽然这种表示法令人困惑),但结果是特别针对Gmail两年前,对于70%的(规则,元素)对,您可以在检查规则最右侧选择器的tag / class / id部分后判断规则不匹配。 Mozilla的页面加载性能测试套件的相应数量为72%。因此,尽可能快地摆脱所有规则中的2/3是非常值得的,然后只担心匹配剩余的1/3。

    另请注意,浏览器已经进行了其他优化,以避免尝试匹配绝对不匹配的规则。例如,如果最右边的选择器有一个id并且id与元素的id不匹配,那么在Gecko中根本不会尝试将该选择器与该元素匹配:尝试使用"具有ID的选择器"的集合来自元素ID的哈希表查找。因此,在考虑最右边的选择器的标签/类/ id之后,这是70%的具有很好匹配机会的规则仍然不匹配。


    从右到左解析,也称为自下而上解析实际上对浏览器有效。

    考虑以下:

    1
    #menu ul li a { color: #00f; }

    浏览器首先检查a,然后是li,然后是ul,然后是#menu

    这是因为当浏览器正在扫描页面时,它只需要查看当前元素/节点以及它已扫描的所有先前节点/元素。

    需要注意的是,浏览器开始处理它获得完整标记/节点的时刻,除了找到脚本之外不需要等待整个页面,在这种情况下它暂时暂停并完成脚本的执行然后前进。

    如果反之亦然,那将是低效的,因为浏览器在第一次检查时发现了它正在扫描的元素,但后来被迫继续查看所有其他选择器的文档。为此,浏览器需要拥有整个html,并且可能需要在开始css绘制之前扫描整个页面。

    这与大多数lib解析dom的方式相反。在那里构建了dom,它不需要扫描整个页面,只需找到第一个元素,然后继续匹配其中的其他元素。


    它允许从更具体到更具体的级联。它还允许应用中的短路。如果更具体的规则适用于父规则适用的所有方面,则忽略所有父规则。如果父级中还有其他位,则应用它们。

    如果你反过来,你会根据父母进行格式化,然后每当孩子有不同的东西时覆盖。从长远来看,这比忽略已经处理的规则中的项目要多得多。