Open5

@scope

ユイト🍓ユイト🍓

@scopeルール

セレクタの適用範囲を指定できるルール。
より的を絞ったマッチングをするために使用できる。

スコープの有効範囲

スコープの上限(scoping root)と下限(scoping limit)を設定できる。
スコープの範囲は、「scoping rootの子孫要素かつ、scoping limitの子孫要素でない」となる。
今のところ、scoping rootとscoping limitに選ばれた要素は、スコープから除外される。

一般的な例

@scopeに続く()内のセレクタのことをスコープルート(scoping root)と呼ぶ。
スコープルート自身はスコープ範囲に含まれず、スコープルートの子孫要素が含まれる。

html
<div class="hoge">
  <a href="#">スコープにマッチした要素</a>
</div>
<a href="#">スコープにマッチしない要素</a>
css
@scope (.hoge) {
//.hogeの子孫のa要素が対象。
 a {
     color:red;
  }
}

スコープ制限を設けた時の例

スコープ制限を設定するときは、scoping rootに続いて「to」キーワードの後()内にセレクタを指定する。

html
<div class="scoping-root">
  <a href="#">スコープにマッチする要素</a>
  <div class="scoping-limit">
    <a href="#">スコープにマッチしない要素</a>
  </div>
  <a href="#">スコープにマッチする要素</a>
</div>
css
@scope (.scoping-root) to (.scoping-limit) {
  //class名「scoping-roo」の子孫要素かつ、class名「scoping-limit」の子孫要素でないa要素が対象
  a {
    color:red;
  }
}

スコープ制限自体はスコープ範囲に含まれない。

@scopeルール内でスコープルート自身を選択したい場合、:scopeセレクタを使用する。

@scope (.hoge) {
// .hogeが対象
 :scope {
    color:red;
  }
}
ユイト🍓ユイト🍓

スコープの効果

  • スコープルート自身の要素をマッチさせる場合は、「:scope」セレクタを使用
  • スコープルートを表すセレクタをマッチさせる場合、「&」セレクタを使用
  • 複数のスコープルートで同じ要素に宣言(プロパティと値のセット)が指定されている場合、詳細度や出現順序に関係なく、宣言した要素と距離が一番近いスコープルートの宣言が優先される
  • スコープ内では、CSSの入れ子とは異なり、スコープルートのセレクタの詳細度は含まれない
html
<div id="root">
 <p>rootの詳細度は含まれない</p>
</div>
css
@scope (#root) {

 p {
   /*詳細度は(0,0,1)*/
    color:red;
  }
}

微妙に違うけど:where(#root) p {color:red}と同じ

ユイト🍓ユイト🍓

質問

@scopeルール文において:scopeセレクタと&セレクタのマッチングにおける違いについて知りたい。

背景

Chorme118から導入される@scopeルールについて勉強しています。
:scopeと&セレクタの違いについて分かっている部分とそうでない部分があるため質問しました。

分かっている部分

詳細度が異なることです。

  • :scopeの場合、詳細度は擬似クラスと同等になる。
  • &の場合、詳細度は<scoping-start>の中で最も詳細度の高いセレクタと同等になる。

html
<p id="scoping-root">
  りんご
</p>
css
@scope (#scoping-root) {
    &  {
      /*&の詳細度は(1,0,0)*/
      color:red;
     }
    :scope {
     /*:scopeの詳細度は(0,1,0)*/
     color:green;
    }
}

よってcolorはredが適用される。

分かっていない部分

以下の仕様書の説明が理解できていません↓

scopeセレクタはスコープルートそのものにのみマッチしますが、&セレクタは<scope-start>セレクタリストにマッチする要素すべてにマッチします。(原文をDeepLで翻訳)

引用部分のURL↓
https://drafts.csswg.org/css-cascade-6/#:~:text=Differences in selector matching

前半の:scopeについての説明は分かります。
後半の&セレクタの説明がよく分かりません。

僕は、以下のように&が<scoping-start>に書かれたセレクタで置き換えられると解釈しました↓

<p class="scoping-root">
  りんご
</p>
@scope (.scoping-root) {
  & {
    color:red
  }
}
/*↑のルールは↓のルールと同じだと解釈*/
@scope (.scoping-root) {
  .scoping-root {
    color:red
  }
}

この場合のスコープにマッチする要素は、「.scoping-rootの子孫要素の中にある.scoping-root」となりcolorの指定は適用されないはずが、適用されました。

そのため、&もスコープルート自身を指すと解釈しました。

しかし、@scopeを入れ子にした場合は、<scoping-start>で書かれたセレクタで置き換えられ、「scoping-rootの子孫要素かつspanの子孫要素のspan要素」となりcolorは適用されませんでした↓

  <p class="scoping-root">
    <span>りんご</span>
  </p>
@scope (.scoping-root) {
  @scope (span) {
    &  {
      color:red;
    }  
  }
}

入れ子の有無で適用される・されない場合があり混乱です。

仕様書のURL

https://drafts.csswg.org/css-cascade-6/

:scopeセレクタと&セレクタのマッチングにおける違いについて知りたい。

ユイト🍓ユイト🍓

@scopeの構文

css
@scope [(<scope-start>)]? [to (<scope-end>)]? {
  <rule-list> 
}

<scope-start>にはセレクタを記述する。スコープルートを特定するために使われる。
<scope-end>もセレクタを記述する。スコープ制限を特定するために使われる。
<rule-list>とは、CSSのルールが複数あるもの。
ルールとはセレクタと宣言ブロックのまとまり↓

p {
/*pがセレクタ、「{ color:red}」が宣言ブロック*/
 color:red;
}

角括弧([])はグループ分けのために使われる。
クエスチョンマーク(?)は直前の単語、型、グループが省略可能であることを表す。
つまり、scope-startとscope-endは省略可能。

注意点として、擬似要素(::after、::beforeなど)はscope-start、scope-endどちらにも使用できない。