作成者が定義した CSS 名と Shadow DOM は連携して動作します。ただし、ブラウザは仕様と一致しておらず、互いに一致していない場合もあります。また、CSS 名はすべて、わずかに異なる方法で不整合があります。
この記事では、作成者定義の CSS 名がシャドウ スコープ間でどのように動作するかの現状を説明します。これは、近い将来の相互運用性の向上に役立つことを願っています。
作成者定義の CSS 名とは
作成者定義の CSS 名は、比較的古い CSS 構文メカニズムです。これは、<keyframe-name> をカスタム識別子または文字列として定義する @keyframes ルール用に最初に導入されました。このコンセプトの目的は、スタイルシートの一部で何かを宣言し、別の部分で参照することです。
/* "fade-in" is a CSS name, representing a set of keyframes */
@keyframes fade-in {
  from { opacity: 0 };
  to { opacity: 1 }
}
.card {
  /* "fade-in" is a reference to the above keyframes */
  animation-name: fade-in;
}
CSS 名を使用する他の CSS 機能には、フォント、プロパティ宣言、コンテナクエリ、最近ではビュー遷移、アンカー配置、スクロール駆動アニメーションなどがあります。次の表に、Chrome が状態を確認する名前を示します(ただし、網羅的なものではありません)。
| 機能 | 名前の宣言 | 名前の参照 | 
|---|---|---|
| キーフレーム | @keyframes | 
      animation-name | 
    
| フォント | @font-face { }
      @font-palette-values | 
      font-family
      font-palette | 
    
| プロパティの宣言 | @property未登録のカスタム プロパティ宣言  | 
      var() | 
    
| 遷移を表示する | view-transition-name
      view-transition-class | 
      ::view-transition-* 疑似要素 | 
    
| アンカーの配置 | anchor-name | 
      position-anchor | 
    
| スクロール駆動アニメーション | view-timeline-name
      scroll-timeline-name | 
      animation-timeline | 
    
| リストのスタイル | @counter-style | 
      list-style | 
    
| カウンタ | counter-reset
      counter-set
      counter-increment | 
    |
| コンテナクエリ | container-name | 
      @container | 
    
| ページ | page | 
      @page | 
    
表に示すように、通常、CSS の名前には対応する CSS の参照があります。たとえば、animation-name は @keyframes という名前への参照です。CSS 名は、属性名やタグ名など、DOM で定義された名前とは異なります。CSS 名は、スタイルシートのコンテキスト内で宣言されてから参照されます。
名前と Shadow DOM の関係
CSS 名は、ドキュメントまたはスタイルシートのさまざまな部分の間に関係を作成するように構築されていますが、シャドー DOM は、その逆を行うように構築されています。関係をカプセル化するため、独自の名前空間を持つはずのウェブ コンポーネント間で漏洩しません。
CSS 名とシャドー DOM を組み合わせることで、柔軟性がありながら安定性も確保された、表現力豊かなウェブ コンポーネントの作成が可能になります。
理論上はこれは良い方法です。実際には、同じブラウザ内の機能間、ブラウザ間、機能と仕様間で、CSS 名が Shadow DOM と相互運用する方法に一貫性がありません。
名前とシャドー DOM の連携の仕組み
この問題を理解するには、理論上、CSS のこれらの部分がどのように連携する必要があるかを理解することが重要です。
一般的なルール
シャドウ ツリー間での CSS 名の動作に関する一般的なルールは、CSS スコープ レベル 1 仕様で定義されています。要約すると、CSS 名は定義されているスコープ内でグローバルです。つまり、子孫シャドー ツリーからはアクセスできますが、兄弟シャドー ツリーや祖先シャドー ツリーからはアクセスできません。これは、同じツリー スコープ内にカプセル化される要素 ID などのウェブ プラットフォームの名前とは異なります。
ルールの例外: @property
他の CSS 名とは異なり、CSS プロパティはシャドー DOM でカプセル化されません。むしろ、さまざまなシャドウ ツリー間でパラメータを渡す一般的な手段です。これにより、@property 記述子は特別なものになります。これは、特定の名前付きプロパティの動作を定義するドキュメント全体の型宣言のように動作します。プロパティはシャドー ツリー間で一致している必要があるため、プロパティ宣言が一致しないと予期しない結果が生じます。そのため、@property 宣言は、ドキュメント順にフラット化され、解決されるように指定されています。
::part でルールがどのように機能するか
シャドウパートは、シャドウツリー内の要素を親ツリーに公開します。これにより、親ツリーはその要素にアクセスし、::part 要素を使用してスタイルを設定できます。
::part では、2 つのツリー スコープが同じ要素にスタイルを適用できるため、次のカスケード順序が指定されます。
- まず、シャドウ コンテキスト内のスタイルを確認します。これは、パーツの「デフォルト」スタイルです。
 - 次に、
::partで定義されている外部スタイルを適用します。これは、パーツの「カスタマイズされた」スタイルです。 - 次に、
!importantとともに定義された内部スタイルを適用します。これにより、カスタム要素で、特定のパートの特定のプロパティが::partでカスタマイズできないことを宣言できます。 
つまり、::part はシャドウ スコープのスタイルではなくホスト スコープのスタイルであるため、シャドウ DOM 内の名前を ::part から参照することはできません。次に例を示します。
// inside the shadow DOM:
@keyframes fade-in {
  from { opacity: 0}
}
// This shouldn't work!
// The host style shouldn't know the name "fade-in"
::part(slider) {
  animation-name: fade-in;  
}
インライン スタイルでのルールの動作
::part とは異なり、style 属性を持つインライン スタイル、またはスクリプトを使用してプログラムでスタイルを設定するスタイルは、要素のスコープに制限されます。これは、要素にスタイルを適用するには、要素ハンドル、つまりシャドウルート自体にアクセスする必要があるためです。
CSS 名と Shadow DOM が実際に連携する仕組み
上記のルールは明確かつ一貫していますが、現在の実装では必ずしも反映されていません。実際には、@property はブラウザ間で一貫して仕様と異なる動作をします。また、他の機能のほとんどには未解決のバグがあります(一部はまだリリースされていないため、修正する時間があります)。
これらの機能が実際にどのように機能するかをテストして示すために、https://css-names-in-the-shadow.glitch.me/ というページを作成しました。このページには、いくつかの iframe があり、それぞれが 1 つの機能に焦点を当て、次の 6 つのシナリオをテストします。
- 外側の名前への外部参照: Shadow DOM は使用されません。問題なく動作します。
 - 内部名への外部参照: シャドー コンテキストで定義された名前が漏洩することを意味するため、これは機能しません。
 - 外側の名前への内部参照: ツリー スコープの名前はシャドウルートに継承されるため、これは機能します。
 - 内部名への内部参照: 参照の名前が同じスコープにあるため、これは機能するはずです。
 ::partが外部名を参照している:::partと名前の両方が同じスコープで宣言されているため、これは機能します。::part内部名への参照: 外部スコープはシャドー DOM 内で宣言された名前を認識できないため、これは機能しません。
@keyframes
仕様で定義されているように、@keyframes アットルールが祖先スコープ内にある限り、シャドウルート内からキーフレーム名を参照できます。実際には、この動作を実装しているブラウザはなく、キーフレーム定義は定義されているスコープでのみ参照できます。問題 10540 をご覧ください。
@property
仕様で定義されているように、@property の宣言はドキュメント スコープにフラット化されます。ただし、現時点では、すべてのブラウザでドキュメント スコープでのみ @property を宣言でき、シャドウルート内の @property 宣言は無視されます。
問題 10541 をご覧ください。
ブラウザ固有のバグ
他の機能は、ブラウザによって動作が異なります。
@font-faceは Safari でルート スコープにフラット化されます。- Chromium でシャドールートの 
anchor-nameルールを継承できない scroll-timeline-nameとview-timeline-nameは::partで正しくスコープ設定されていません(Chromium でも同様です)。- シャドウルートで 
@font-palette-valuesを宣言することは、どのブラウザでも許可されていません。 view-transition-classはシャドールート内で定義できます(遷移自体はシャドールートの外部にあります)。- Firefox では、
::partが内部シャドウ名(コンテナクエリ、キーフレーム)にアクセスできます。 - Firefox と Safari は、シャドールートの 
@counter-styleを尊重しません。 
counter-reset、counter-set、counter-increment は暗黙的な名前であるため、ルールが若干異なります。CSS プロパティの宣言には、確立された、十分にテストされた一連のルールがあります。
まとめ
残念ながら、CSS 名と Shadow DOM に関する現在の相互運用状態のスナップショットを調べると、エクスペリエンスが不整合でバグがあります。ここで検討した機能は、ブラウザ間で一貫した動作をせず、仕様に準拠していません。ただし、エクスペリエンスを一貫させるための差分は、バグと仕様の問題の有限なリストです。これを修正しましょう。なお、この記事で説明する不整合に困難を感じている場合は、この概要が役立つことを願っております。