: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
可恶!在第一个示例中,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
是否能够提升性能。所以...就像一名优秀的工程师一样,我发起了一项测试。我的理由:浏览器进行选择器匹配的界面区域越小,查找速度就越快。
在我的实验中,WebKit 目前花费的时间是不使用 :scope
的大约 1.5-2 倍。糟糕!修复 crbug.com/222028 后,从理论上说,与不使用它相比,使用它应该会略微提升性能。