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

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 后,与不使用该功能相比,理论上使用该功能应该会略微提升性能