:scope
在 CSS 选择器 4 中的定义如下:
一种伪类,表示上下文引用元素集中的任何元素。这是一个(可能为空)显式指定的元素集,例如由
querySelector()
指定的元素,或<style scoped>
元素的父元素,用于“限定”选择器,使其仅在子树内进行匹配。
以下是在 <style scoped>
中使用此方法的示例(了解详情):
<style>
li {
color: blue;
}
</style>
<ul>
<style scoped>
li {
color: red;
}
:scope {
border: 1px solid red;
}
</style>
<li>abc</li>
<li>def</li>
<li>efg</li>
</ul>
<ul>
<li>hij</li>
<li>klm</li>
<li>nop</li>
</ul>
这会将第一个 ul
中的 li
元素着红色,并且由于 :scope
规则,会在 ul
周围添加边框。这是因为在此 <style scoped>
的上下文中,ul
与 :scope
匹配。它是本地情境。如果我们在外部 <style>
中添加 :scope
规则,则该规则会与整个文档匹配。本质上等同于 :root
。
情境元素
您可能已经知道 querySelector()
和 querySelectorAll()
的 Element
版本。您可以将结果集限制为上下文元素,而不是查询整个文档:
<ul>
<li id="scope"><a>abc</a></li>
<li>def</li>
<li><a>efg</a></li>
</ul>
<script>
document.querySelectorAll('ul a').length; // 2
var scope = document.querySelector('#scope');
scope.querySelectorAll('a').length; // 1
</script>
调用这些方法时,浏览器会返回经过过滤的 NodeList
,其中仅包含 a.) 与选择器匹配且 b.) 也是上下文元素的后代的一组节点。因此,在第二个示例中,浏览器会找到所有 a
元素,然后滤除不在 scope
元素中的元素。这种方法虽然可行,但如果不小心,可能会导致一些奇怪的行为。请继续阅读。
querySelector 出错时
选择器规范中有一个非常重要的要点,人们常常会忽略。即使对某个元素调用了 querySelector[All]()
,选择器仍会在整个文档上下文中进行评估。这意味着可能会发生意外情况:
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
WTF! 在第一个示例中,ul
是我的元素,但我仍然可以使用它并匹配节点。在第二种情况下,body
甚至不是我的元素的后代,但“body ul a
”仍然匹配。这两种情况都会令人困惑,并且不符合您的预期。
这里值得与 jQuery 进行比较,它采用了正确的方法,并执行了您预期的工作:
$(scope).find('ul a').length // 0
$(scope).find('body ul a').length // 0
...输入 :scope
即可解决这些语义问题。
使用 :scope 修复 querySelector
WebKit 最近支持在 querySelector[All]()
中使用 :scope
伪类。您可以在 Chrome Canary 27 中对其进行测试。
您可以使用它将选择器限制为上下文元素。我们来看一个示例。在以下示例中,:scope
用于将选择器“限定”到作用域元素的子树。没错,我说了三次范围!
scope.querySelectorAll(':scope ul a').length); // 0
scope.querySelectorAll(':scope body ul a').length); // 0
scope.querySelectorAll(':scope a').length); // 1
使用 :scope
可以提高 querySelector()
方法的语义可预测性,并内嵌到其他方法(如 jQuery)已经在执行的操作。
效果胜出?
还没 :(
我想知道在 qS/qSA 中使用 :scope
是否会提升性能。于是,我像一个优秀的工程师一样,快速编写了一个测试。我的推理是:浏览器执行选择器匹配的表面区域越小,查找速度就越快。
在我的实验中,与不使用 :scope
相比,WebKit 目前需要的时间大约是 1.5-2 倍。糟糕!修复 crbug.com/222028 后,与不使用该功能相比,理论上使用该功能应该会略微提升性能。