CSS :scope 虛擬類別的用途為何?

:scopeCSS 選取器 4 中定義為:

此為偽類別,代表內容參照元素集中的任何元素。這是一個 (可能為空白) 明確指定的元素組合,例如由 querySelector() 指定的元素,或是 <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!

    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 的問題後,理論上應該能稍微提升效能,而非使用效能。