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