CSS :scope 伪类的用途是什么?

:scopeCSS 选择器 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 后,从理论上说,与不使用它相比,使用它应该会略微提升性能。