css - 高效和低效的 CSS 选择器(根据 Google、PageSpeed ...)

标签 css css-selectors pagespeed

在尝试减小网页的 HTML 大小时,我遇到了 Google 和 PageSpeed Firefox 附加组件的 CSS 选择器重新加载效率的建议,这(几乎)让我重新考虑更改:

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

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

Descendant selectors are inefficient because, for each element that matches the key, the browser must also traverse up the DOM tree, evaluating every ancestor element until it finds a match or reaches the root element. The less specific the key, the greater the number of nodes that need to be evaluated.

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

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

ID selectors are unique by definition. Including tag or class qualifiers just adds redundant information that needs to be evaluated needlessly.

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

div#foo { color: black; } #foo { color: white; }

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

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

编辑:

我对生成的页面做了一些实验,看起来浏览器对后代选择器的处理确实很可怜:

页面包含(缩写):

#top a {text-decoration: none;}

#foo1 a.foo {color: red;}

#foo2 a.foo {color: red;}

[... repeated 10000 times]

<body id=top>

<div>...[nested 50 times]<a href=foo>bla</a></div>[...]

[previous line repeated 10000 times]

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

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

.foo类选择器已从非应用规则中删除,页面在 Safari 5 和 Firefox 3.6.10 中分别需要大约 200 秒和 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 等)。

最佳答案

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

您将了解浏览器如何计算表达式以及某些选择器效率低下的原因。

帖子中的相关引用:

CSS gets evaluated from right to left.

To determine whether a CSS rule applies to a particular element, it starts from the right of the rule and works it's way left.

If you have a rule like body div#content p { color: #003366; } then for every element—as it gets rendered to the page—it'll first ask if it's a paragraph element. If it is, it'll work its way up the DOM and ask if it's a div with an ID of content. If it finds what it's looking for, it'll continue its way up the DOM until it reaches the body.

By working right to left, the browser can determine whether a rule applies to this particular element that it is trying to paint to the viewport much faster. To determine which rule is more or less performant, you need to figure out how many nodes need to be evaluated to determine whether a style can be applied to an element.

关于css - 高效和低效的 CSS 选择器(根据 Google、PageSpeed ...),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3958627/

相关文章:

CSS 选择器不是元素类型的子元素?

css - 继承多个nth-child时重置nth-child "clear: both"

javascript - PhoneGap/ Cordova : cannot prevent scrolling

css - Spry 验证文本字段在谷歌浏览器中显示不佳

javascript - 将多个div中的rgb值替换为十六进制

html - 我可以同时激活所有子悬停状态吗?

html - 什么是 HTML 和 CSS 图像的最佳实践

javascript - 优化我的网站使用但不在我的网站上的 Javascript 和 CSS?

javascript - 为什么我的 Google PageSpeed Insights 得分降低了这么多?

android - Webview 仅在新设备​​上全屏显示,在旧设备上不显示