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

內容相關元素

您可能已經知道 Element 版本的 querySelector()querySelectorAll()。您不必查詢整份文件,而是將結果集限制為關聯元素:

<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 的時間比未使用 :scope 大約 1.5 到 2 倍。乾杯!在修正 crbug.com/222028 後,理論上應該可以稍微提升效能,而不使用。