10

在尝试减小网页的 HTML 大小时,我遇到了 Google 和 PageSpeed Firefox Add-On 的建议,它们提高了 CSS 选择器的效率,这(几乎)让我重新考虑了这些更改:

http://code.google.com/intl/de-DE/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors

具体来说,后代选择器非常适合使用 ID 或 CLASS 属性选择整个块(例如 DIV),然后使其所有子元素都没有 CLASS/ID 属性。但如果应用规则的遍历顺序如谷歌所述,则不应使用它们:

后代选择器效率低下,因为对于每个匹配键的元素,浏览器还必须遍历 DOM 树,评估每个祖先元素,直到找到匹配项或到达根元素。密钥越不具体,需要评估的节点数量就越多。

我非常怀疑浏览器是否使用了如此低效的遍历顺序,当然它们只会处理与顶部选择器组件匹配的元素的子树,即#foo span {...} 仅应检查 #foo 以下的元素,而不是每个跨度。查看最近浏览器代码的任何人都可以确认/否认这一点吗?

第二个有问题的建议是关于过度限定的选择器:

ID 选择器根据定义是唯一的。包含标签或类限定符只会添加需要进行不必要评估的冗余信息。

如果 ID 选择器根据定义是唯一的,为什么浏览器需要检查冗余信息?我知道他们这样做是因为例如,

div#foo { 颜色:黑色;} #foo { 颜色:白色;}

会导致 a 中出现黑色文本<div id=foo>,但是 a) 它不应该完成(?需要 W3C 参考)和 b) 我不明白为什么当它导致对元素的简单 O(1) 检查时它会明显变慢标签名。

任何与现代浏览器源代码关系良好的人都可以阐明这些说法吗?由于大多数现代网站都使用后代选择器(包括 SO)并且它们具有明显的优势,所以我非常想使用它们......

编辑:

我对生成的页面进行了一些实验,似乎浏览器对后代选择器的处理确实很可怜:

包含(缩写)的页面:

#top a {文本装饰:无;}

#foo1 a.foo {颜色:红色;}

#foo2 a.foo {颜色:红色;}

[...重复 10000 次]

<主体标识=顶部>

<div>...[嵌套 50 次]<a href=foo>bla</a></div>[...]

[上一行重复 10000 次]

(基本上 10000 行,每行有 50 个嵌套的 div,要遍历到根节点和 1 个匹配的 10000 个选择器)

使用 Safari 5 在 2.2 秒内加载和呈现(直到window.onload()执行的时间),使用 Firefox 3.6.10 只需不到 10 秒。

.foo从非应用规则中删除类选择器时,页面在 Safari 5 中大约需要 200 秒,在 Firefox 3.6.10 中大约需要 96 秒。这说明了后代选择器的实现有多么糟糕(在这种情况下,10000 条规则中的每一条都可能导致遍历到#top,在该规则失败的地方)。

儿童选择器的表现如何?#foo > span > div > div > div > div > div a {color: red;}(也从不匹配,但强制遍历 6 个父节点)使用 Safari 5 需要 27 秒,使用 Firefox 3.6.10 需要 31 秒。

结论

后代选择器和子选择器目前在主流浏览器上都很糟糕。如果您关心速度,最好为所有样式标签添加丑陋的 class/id 属性,至少对于非常常见的 HTML 标签(如 a、img、div 等)。

4

1 回答 1

9

看看 Jonathan Snook 最近的这篇文章:http: //snook.ca/archives/html_and_css/css-parent-selectors

您将看到浏览器如何评估表达式以及某些选择器效率低下的原因。

该帖子的相关引用:

CSS 从右到左进行评估。

要确定一条 CSS 规则是否适用于特定元素,它从规则的右侧开始,并沿左侧运行。

如果你有像 body div#content p { color: #003366; 这样的规则 } 然后对于每个元素——当它被渲染到页面时——它会首先询问它是否是一个段落元素。如果是,它会沿着 DOM 向上运行,并询问它是否是具有内容 ID 的 div。如果它找到了它正在寻找的东西,它将继续沿着 DOM 向上移动,直到它到达正文。

通过从右到左工作,浏览器可以确定规则是否适用于它试图更快地绘制到视口的特定元素。要确定哪个规则的性能更高或更低,您需要确定需要评估多少个节点才能确定是否可以将样式应用于元素。

于 2010-10-18T11:53:01.007 回答