これまでセレクターの適用範囲を絞るためにはCSSの詳細度を高めることで実現してきたと思います。
詳細度を高めずにセレクターの適用範囲を設定できる@scope
についてまとめます。
@scope
のブラウザサポート状況
2023年11月11日時点でのブラウザサポート状況です。
Chromeの118からサポートされた@scope
は、SafariやFirefoxでは利用できないようなので、気にせず利用できるようになるまでにはもう少しかかりそうです。
@scope
の使い方
使い方は簡単です。
.hoge
の子要素にあるspanタグのテキストを赤色にしたい場合は下記のように書きます。
@scope (.hoge) {
span {
color: red;
}
}
@scope
の利点
はじめに記述した通り、CSSの詳細度をあげることなくスタイルを当てることができます。
// 従来の指定:詳細度(0.1.1)
.hoge {
span {
color: red;
}
}
// @scopeを使った場合:詳細度(0.0.1)
@scope (.hoge) {
span {
color: red;
}
}
@scope
で使用したセレクターは詳細度に影響を与えることはありません。
なので@scope
を使って指定したspanタグは下記のclassでも上書きできます!
.blue {
color: blue;
}
ドーナッツスコープ
初めて聞きましたが、指定した要素の間に設置された要素に対してスタイルを適用する方法のことをドーナッツスコープといいます!(知らんかった…)
@scope (.hoge) to (.hoge-inner) {
span {
color: red;
}
}
:scope
擬似クラスについて
擬似クラスを利用することでスコープの対象にしたセレクターに対してスタイルを当てることが可能です!
@scope (.hoge) {
:scope {
// .hogeに対してスタイルを当てられる
}
}
また、対象にした子要素に対してスタイルを当てたい時はいくつか方法があります!
@scope (.hoge) {
// ①
span {
color: red;
}
:scope span {
// .hogeの子要素であるspanにスタイルを当てる「①」と同じ
}
& span {
// .hogeの子要素であるspanにスタイルを当てる「①」と同じ
}
}
複雑な要件も実現できます!
// :scope直下の子要素である場合に適応させたい場合
@scope (.hoge) to (:scope > .hogehoge) {}
// .hogehoge内に:scopeがある場合に適応させたい場合
@scope (.hoge) to (.hogehoge :scope .hogehoge-inner) {}
ただ、下記のような記述はスコープ内にない要素を指定することになるので無効となります…
@scope (.hoge) {
:scope + span {
}
}
@scope
の詳細度
@scope
の中で擬似クラスを利用すると詳細度が上がってしまうことは留意しておいてください!
@scope (.hoge) {
span {
// 詳細度:(0, 0, 1)
}
:scope span {
// 詳細度:(0, 1, 1)
}
& span {
/*
「&」は「is()」糖衣されます
実際には、:is(.hoge) spanとなります
詳細度:(0, 1, 1)
*/
}
}
is()
の詳細度の計算には注意が必要です。
is()
の詳細度は囲まれたセレクターの中で最も高い詳細度のものが計算の対象となります。
is(#hoge, .hoge) span {}
上記の場合詳細度は、is()
の中で最も詳細度が高いのは#hoge
なので詳細度は(1,0,0)となり、
詳細度の合計はその後のspan
と合わせて(1,0,1)となります。
プレリュードなしのスコープ
プレリュードとは@scope
の後につく()
で囲んだ部分のことです。
下記の記述でいうと「.hoge」の部分にあたる箇所です。
@scope (.hoge) {}
プレリュードは<style>
タグを利用してHTMLに直接書くことで省略することができます。
<div class="hoge">
<div class="hogehoge">
<style>
@scope {
color: red;
}
</style>
</div>
</div>
スコープ近接性
CSSのカスケードに新しいステップが追加されました。
これによって同名のclassを入れ子にする場合の制御が便利になりました。
<style>
.red { color: red; }
.blue { color: blue; }
.red span { color: red; }
.blue span { color: blue; }
</style>
<div class="red">
<span>hoge</span>
<div class="blue">
<span>hoge2</span>
<div class="red">
<span>hoge3</span>
</div>
</div>
</div>
上記のスタイリングの結果は以下の画像のようになります。
本来であれば「hoge3」は赤文字になってほしいところですが、カスケードの特性上.blue span
が一番優先されます。
@scope
だと下記のように記述することで上記の問題を解決できます!
<style>
@scope (.red) {
:scope { color: red; }
span { color: red; }
}
@scope (.blue) {
:scope { color: blue; }
span { color: blue; }
}
</style>
まとめ
カスケードの仕組み上、外部スタイルシートの読み込み順や書き順を意識しないといけない場合もありましたが@scope
を利用することでこれまで必要だった思考が必要なくなりそうです!
とはいえまだ最新のブラウザでしか利用できないのでしばらく利用は控えた方が良さそうな印象です。
そもそもReactやVue.jsのようなフレームワークを利用すれば@scope
を使わなくてもスコープを切ってスタイリングができるので実装技術を検討するのも方法かと思います!
プレーンなCSSでスタイルの定義が分離できるのはコードの見通しが良くなり修正のしやすさもUPできるのは良いですね!
参考リンク