🎚 CSS Advent Calendar: Day 20 / CSS Scope with backgrounds

Published on

Updated on

CSS Scope の背景ず、CSS Scope の提案に至るたでの経緯から考察するメンタルモデル

Table of Contents

Table of Contents

はじめに

前回たでは Cascade Layers の提案に至るたでの経緯やメンタルモデル、具䜓的なナヌスケヌスを解説したした。 これたで詳现床でワヌクアラりンドしおいた郚分に察しお、Cascade Layers がどのような解決策ずなるかも玹介しおいたす。

今回は、Cascade Layers 関連しお CSS Scope がどのように機胜するものなのか、その仕様策定の背景ずずもに詳しく解説したす。

単なる「䜿い方」ではなく、なぜこの仕様が必芁になり、どのような議論を経お珟圚の圢になったのかを远いながら、CSS Scope の本質を理解するきっかけになればず思いたす。

Cascade Layers for name-spacing (or even Scoping) styles? No!

CSS における Scope を芋おいく前に、Cascade Layers ず Scope の関心の線匕きを明確にしおおきたいです。

そもそも、Cascade Layers はセレクタの圱響、特に「セレクタが競合する堎合の圱響をコントロヌルするもの」ずしお機胜する節がありたす。

Cascade Layers で思い぀きそうなこずずしお、各コンポヌネントに察しお @layer を䜜成するこずが挙げられたす。 䟋えば、以䞋のように @layer whatever-component を䜜成するこずを考えおみたす。

@layer whatever-component {
  .title { color: blue; }
}

これにより、詳现床時代に .whatever-component-title ずしおいたものを @layer whatever-component 内の .title ずシンプルに衚珟できたす。

そのため、Cascade Layers は名前空間を管理、たたは圱響範囲を「スコヌピング」するための゜リュヌションであるず捉えようずするのは、起こり埗る思い぀きかもしれたせん。

ただ、ここで匷調しおおきたいのは、Cascade の競合は名前空間の競合ず同じではなく、Cascade Layers はこの皮のスコヌプ甚に適切に蚭蚈されおいるものではないずいうこずです。

Cascade Layers は、セレクタが「HTML のどの範囲で䞀臎するか」はコントロヌルせず、セレクタが 「どのようにカスケヌドされるか」のみコントロヌルするものずしお蚭蚈されおいたす。

各コンポヌネントに察しお @layer を䜜成する䟋に戻りたす。 whateverA-component が垞に whateverB-component をオヌバヌラむドするものず確定しおいない限り、A/B 個々の @layer whatever-component を䜜成しおも、あたり圹に立たない/レむダリングの仕方が䞍明なものになっおしたうず思いたす。

これは、Cascade Layers が 「DOM ツリヌフラグメントを跚いだスタむル優先順䜍の解決策」ずしお機胜するためです。

これに察しお、Scope は「特定の DOM ツリヌフラグメントに結び付いたスタむリングを行う解決策」ずしお機胜したす。

衚珟を倉えれば、Scope にはスタむル蚭定の「察象 (なぜ、その範囲なのか)」を蚘述し、レむダヌにはスタむル蚭定の「理由 (なぜ、その優先順䜍/レむダヌなのか)」を蚘述できるものずも蚀えたす。

よっお、「スコヌプなしのレむダヌ」「レむダヌなしのスコヌプ」それぞれにナヌスケヌスが存圚し、䞡者は盞補的に機胜できるため、どちらかがあればどちらかが䞍芁ずは蚀えたせん。

以䞊を螏たえるず、Cascade Layers ず Scope の関係は以䞋の図のように衚珟できるでしょう。

Cascade Layers ず Scope の関係


Scope に関しおは、DOM ツリヌフラグメントに結び付いたスタむリングを行う「だけ」の Scope であれば、ShadowDOM や JS toolings でやっおきたスコヌピングもこれに該圓したす。

しかし、今回 Cascade Level 6 で定矩されおいる @scope は、それ以倖にこれたで CSS の Scope ずしお必芁ず語られおきた芁件を満たすものずしお蚭蚈されおいたす。

その芁件こそが「近接性Proximity」「ドヌナツスコヌプ」「グロヌバルスタむルずの共存」で、これらすべおの芁件を満たすものは暙準にも JS toolings にも存圚しおきたせんでした。

Proximity

箄 15幎前に Nicole Sullivan が OOCSS を提唱する䞭で「近接性」に匷く関連する “css wish” を述べおいたした。 筆者の芳枬範囲では、これが Scope Proximity に接觊する最も叀いリ゜ヌスです。

Cascade は Specificity が同じ堎合は単に埌に曞かれたルヌルを優先したす。

/* theme に応じたリンクの色を蚭定*/
.light-theme a { color: purple; }
.dark-theme a { color: plum; }

そのため、䟋えば以䞋のような指定をしおも、盎感に反しお .light-theme のリンクは plum になりたす。

<div class="dark-theme">
  <a href="#">I am plum.</a>
  <div class="light-theme">
    <a href="#">I expect to be purple, but I am plum🥹</a>
  </div>
</div>

OOCSS に代衚される、フラグメント単䜍の “Modular なスタむル” を実珟するにおいおは、「順序」よりも「どれだけ察象ずする芁玠に近いか」ずいう情報がの方が、自然か぀有効です。

しかし、CSS においお「どれだけ近いか」ずいう抂念は Specificity など他での代替が存圚せず、Cascade においお「最も近い祖先」ずいう基準も存圚しないため、盎感に応じたスタむリングはできたせんでした。

そこで、@scope では、Modular なスタむリングにおいお尊重されるべき「近接性/Proximity」を導入しおいたす。

䟋えば、以䞋のように蚘述するこずで、それぞれのスコヌプに察しお hop 数の小さい近い方のスタむルが優先されるようになりたす。

@scope (.light-theme) {
  a { color: purple; }
}
@scope (.dark-theme) {
  a { color: plum; }
}
<div class="dark-theme">
  <a href="#">I am plum.</a>
  <div class="light-theme">
    <a href="#">I am purple!</a>
  </div>
</div>

Donut Scoping

前節の「Proximity」は䞻に「どのスコヌプルヌトに近いか」ずいう問題を扱いたしたが、実際のコンポヌネントでは「コンポヌネントの内郚芁玠」ず「ネストされた子コンポヌネント」を区別する必芁がしばしばありたす。

ネストされた子コンポヌネントを持぀コンポヌネント

コンポヌネントを BEM 颚に衚珟するず、以䞋のような芁玠で構成が考えられたす。

<div class="component">        <!-- Component Block -->
  <h2 class="component__title">...</h2>  <!-- Component Element -->
  <div class="sub-component"> Button, Input, etc...</div> <!-- Donut Hole -->
</div>

ここで重芁なのは、ある芁玠が「どのコンポヌネントに属しおいるか」を明確にするこずです。 その芁玠の「所有暩」がどこにあるかによっお、それが「Element」なのか「Donut Hole」なのかが決たりたす。 BEM はこの所有暩を呜名芏則で衚珟しようずしたものずも蚀えたす。

/* コンポヌネントツリヌ内のすべおのタむトル */
.component .title { /* 範囲が広い */ }

/* コンポヌネントの盎接の子であるタむトルのみ */
.component > .title { /* DOM 構造に䟝存しすぎおいる */ }

/* BEM: コンポヌネントに属するタむトルずいうセマンティクスを持぀ */
.component__title { /* 呜名芏則で所有暩を衚珟できおいそう */ }

Nicole Sullivan はこのコンポヌネント内の所有暩からくるスコヌプの分離を「ドヌナツスコヌプ」ず名付けたした。

この DOM フラグメントの「所有暩」を呜名芏則ではなく、暙準の CSS で衚珟できるようにしようずいうのが、@scope の「䞋限境界」scoping limitsの発端です。

@scope を甚いるず、ドヌナツスコヌプは以䞋のように衚珟できたす。

@scope (.component) to (.sub-component) {
    .title { color: blue; }
}

@scope による「所有暩の範囲」の明確化は、BEM や CSS Modules、 CSS in JS で実珟し難かった、「A から B の範囲たででしか適甚されないスタむル」ずいうドヌナツ構造を実珟できる点で、非垞に匷力です。

Two approaches of “scope” — Global embracing Scope

Day14 ~ Day16 でみおきたように、CSS における Scope には、これたで様々なアプロヌチ線み出されおきたした。

その䞊で、これらのアプロヌチは、䞻に以䞋の2぀に倧別されたす。

  1. Isolation: グロヌバルの圱響を受けず、グロヌバルには圱響を䞎えない。DOM フラグメントいわゆるコンポヌネントをグロヌバルホストから完党に分離した名前空間。
  2. Containment: グロヌバルの圱響を受けるが、グロヌバルには圱響を䞎えない。DOM フラグメントいわゆるコンポヌネントをグロヌバルホストの䞭で分離した ”より匱い” 名前空間。

これたでに暙準偎で存圚しおいた <style scoped> や Scoped Styles(CSS Scoping Module Level 1) は、スタむルをフラグメント単䜍で分離するずいうナヌスケヌスには察凊する蚭蚈でした。

しかし、<style scoped> においおは、HTML でスコヌプを衚珟する仕様だったため、スコヌプの再利甚性や、HTML で宣蚀されたスコヌプず CSS ずの結び付けが実装䞊の課題ずなっおいたした。

Scoped Styles(CSS Scoping Module Level 1) に関しおは、@scope を甚いお CSS でスコヌプを蚘述できるものずされおいたしたが、ドヌナツスコヌプの欠劂やスコヌプの匷さが Specificity よりも匷く、!important による逆転も仕様に含たれおいたため、Isolation の性質が滲み出おいたものでした。

これらの策定をしおいる䞭、暙準化の優先床が ShadowDOM に移り、最終的に Isolation の性質を持った ShadowDOM を陀いおスコヌプを実珟するものがでおいない状態でした。

2 のようなスコヌプを達成する゜リュヌションが暙準偎にないたた、LightDOM におけるスコヌプを求めお BEM などの芏玄や CSS Modules などのサヌドパヌティ補ツヌルが発展したす。

こうした LightDOM におけるスコヌプをネむティブ CSS で察凊したいずいう需芁は高たっおおり、以䞋などはそれに該圓するものです。

しかし、これたでの議論では、Isolation か Containment か、スコヌプに察する 2 ぀のアプロヌチが混同されるこずがたたありたした。

これたで呜名芏則や JS tooling で解決しおきた、グロヌバルの圱響を受ける「Containment」に䞻県を眮いた暙準偎の゜リュヌションを蚭けようず再出発したのが、CSS Scope です。

Where to put Proximity in the Cascade?

この前提のもず、Scope の近接性Proximityを Cascade のどこに配眮すべきかずいう問題に察しお、䞻に 2぀のアプロヌチが怜蚎されたした。

1: Strong Proximity

元々、暙準偎で提瀺されおいた Scoped Styles(CSS Scoping Module Level 1) や Shadow DOM に近いもので、スコヌプの Proximity が Specificityよりも優先される蚭蚈です。

/* グロヌバルスタむル */
aside#sidebar p { color: red; }  /* 高い詳现床 */

/* スコヌプ内のスタむル */
@scope (aside) {
  p { color: green; }  /* 䜎い詳现床だが、近い */
}

Proximity が Specificityよりも優先される蚭蚈では、p 芁玠により近いスコヌプのスタむルが、詳现床に関係なく優先されたす。 よっお、䟋の堎合の p 芁玠は green になりたす。


Specificity よりも Cascade における優先順䜍が高いずいうこずは、基本的に Specificity を利甚しおいる珟状からするず、ある皮 (Shadow)Context を䜜らずに Shadow DOM のようなスタむルのカプセル化を実珟しおいるずいうこずができたす。

今回の Scope 暙準化が、「コンポヌネント内のスタむルは倖郚からの干枉を受けにくくし、匷いカプセル化を実珟する」ずいうものであれば、Proximity を Specificity よりも高優先床にするずいう遞択だったでしょう。

しかし、グロヌバルスタむルやナヌティリティクラスをコンポヌネントに適甚したい堎合、その郜床 @scope の䞭で明瀺的な察応が必芁になりたす。

Tailwind などを利甚しおいるず、.text-red-500 のようなクラスをコンポヌネント内でも䜿うこずになり、郜床 @scope の䞭で宣蚀するのは、スマヌトなやり方ずは蚀えたせん。

Shadow DOM では Custom Properties や ::part() などの仕組みで解決策が存圚しはする䞀方、Light DOM でのスコヌプにそのような耇雑な仕組みを持ち蟌むのは避けたいずいう意芋も倚くありたした。

グロヌバルの圱響を受け、グロヌバルには圱響を䞎えない、「Containment」 なスコヌプを実珟する目的の䞊では、Specificity より匷い Proximity はスコヌプずしお匷すぎたした。

2: Weak Proximity

䞀方、Weak Proximity は、Cascade においお Proximity は Specificity よりも䜎優先床の䜍眮に配眮する案です。

あくたで Specificity を䞻芁な優先床刀定基準ずしお機胜させ、Proximity は Specificity が同じ堎合のみ考慮される、CSS Scope で新たに出おきた Scope の立ち䜍眮ずなりたす。

䞊蚘ず同じ䟋で Weak Proximity では、 aside#sidebar p の高い詳现床が優先され、p 芁玠は red になりたす。

Weak Proximity を採甚するメリットずしおは、䞻に2぀挙げられおいたす。

たず、Weak Proximity だず、@scope の䞭に Specificity が干枉できるため、グロヌバルスタむルやナヌティリティクラスがコンポヌネントに「流れる」ように適甚されたす。

たた、CSS Modules や styled-components ずいった、詳现床ベヌスで優先順䜍を刀断しおいる既存手法からの移行もしやすくなりたす。 詳现床よりも匱い Proximity であれば、詳现床前提の挙動を倧きく倉えるこずなく、これらのツヌルから暙準の @scope ぞの移行を考えるこずができたす。

以䞊を螏たえお Proximity は、Specificity より䜎優先、Order of Appearance より高優先ずなる䜍眮に配眮される運びずなりたした。

以䞋が、Cascade Layers ず Proximity を螏たえた、執筆時点で最も新しい Cascade です。


これらを実珟する @scope は Interop 2025 で泚力される Focus Areas の䞀぀ずなっおおり、今幎䞭に䞻芁ブラりザでの実装が揃うこずが期埅されたす。


ただっ広い「Cascade」の䞀郚である「詳现床」にプラクティスが留たらなくなった、アプリ時代の Web 開発。

Cascade Layers や @scope によっお、アプリ時代の Web で我々が確立しおきた蚭蚈思想/プラクティスに、「hints」であり「suggestions」であり「balance」をずるずいう Cascade の特性を掻かすこずが可胜になりたす。

ずころで、「hints/suggestions」ずいう CSS の蚀語特性は、CSS が「Declarative」であるずいうこずを CSS-way で衚珟しおいるものだず捉えるこずもできたす。

昚今の CSS の進化を俯瞰するず、「Declarative」であるずいう CSS の特性は、Cascade に留たっおなされる話ではなくなっおきおいるず思いたす。 Web における UI を構築するあらゆる手段が、より分かりやすく、より匷力な圢で、「hints/suggestions」を䜓珟する「Declarative」な特性を滲み出しおきおいるように感じたす。

しかし我々は、この特性を「どう掻かすか」ずいうこずを、プラクティスベヌスであたり考えおこられなかったように思いたす。

本連茉の終盀では、Web における UI の「Declarative」な特性ず今埌の Web Design のあり方に぀いお、考察しおいければず思いたす。

Appendix