:scope
は、CSS セレクタ 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.) ノードのセットのみが含まれるようにフィルタされます。そのため、2 番目の例では、ブラウザはすべての a
要素を検出し、scope
要素内にない要素を除外しています。これは問題ありませんが、慎重に行わないと奇妙な動作につながる可能性があります。しっかりと確認しておきましょう。
querySelector が失敗した場合
セレクタの仕様には、見落とされがちな非常に 重要なポイントがあります。要素で querySelector[All]()
が呼び出されても、セレクタはドキュメント全体のコンテキストで評価します。つまり、予期せぬ事態が起こり得ます。
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
なんと!最初の例では、ul
が要素ですが、引き続きこれを使用してノードを照合できます。2 つ目の要素では、body
は要素の子孫でもありませんが、「body ul a
」は引き続き一致します。どちらも混乱を招き、期待するものではありません。
ここでは jQuery と比較してみる価値があります。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
を使用してセレクタの「スコープ」をスコープ要素のサブツリーに設定しています。そうだ、スコープを 3 回言ったよ!
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 を修正すれば、使用しない場合と比べてパフォーマンスがわずかに向上するはずです。