CSS Shadow Parts モジュール Level 1

W3C 作業草案,

この文書についての詳細
このバージョン:
https://www.w3.org/TR/2025/WD-css-shadow-parts-1-20251216/
最新公開バージョン:
https://www.w3.org/TR/css-shadow-parts-1/
編集者草案:
https://drafts.csswg.org/css-shadow-parts/
履歴:
https://www.w3.org/standards/history/css-shadow-parts-1/
フィードバック:
CSSWG 課題 リポジトリ
仕様内インライン
編集者:
Tab Atkins-Bittner (Google)
(Google)
この仕様への編集を提案:
GitHub エディター
テストスイート:
https://wpt.fyi/results/css/css-shadow-parts/

概要

この仕様は、::part() 疑似要素を shadow host 上に定義し、shadow host がスタイル付けの目的で、 その shadow tree から選択した要素を外部ページへ選択的に公開できるようにします。

CSS は、構造化文書 (HTML や XML など)のレンダリングを 画面、紙などに記述するための言語です。

この文書のステータス

この節は、この文書が公開された時点でのステータスを説明します。 現在の W3C 公開文書の一覧 およびこの技術報告の最新リビジョンは、 W3C 標準および草案索引で見つけることができます。

この文書は、 CSS Working Group により、Recommendation track を用いる Working Draft として公開されました。 Working Draft としての公開は、 W3C およびそのメンバーによる承認を意味しません。

これは草案文書であり、 随時、他の文書により更新、置換、 または廃止される可能性があります。 この文書を作業中のもの以外として引用することは不適切です。

フィードバックは、 GitHub で課題を提出する(推奨)ことにより送信してください。 その際、タイトルには次のように仕様コード “css-shadow-parts” を含めてください: “[css-shadow-parts] …コメントの概要…”。 すべての課題およびコメントは アーカイブされます。 代わりに、フィードバックは(アーカイブ済みの)公開メーリングリスト www-style@w3.org へ送信できます。

この文書は、2025年8月18日版 W3C Process Document によって管理されます。

この文書は、W3C Patent Policy の下で運営されるグループにより作成されました。 W3C は、このグループの成果物に関連して行われた特許開示の公開リストを管理しています。 そのページには、特許を開示するための手順も含まれています。 その個人が Essential Claim(s) を 含むと考える特許について実際の知識を持つ個人は、 W3C Patent Policy の section 6 に従ってその情報を開示しなければなりません。

1. はじめに

Shadow DOM により、作者はページを「コンポーネント」、 すなわち、その詳細がコンポーネント自身にのみ関係し、 外部ページには関係しないマークアップの部分木へ分離できます。 これにより、ページのある部分を意図したスタイルが 誤って過剰に適用され、ページの別の部分の見た目を誤らせる可能性が低減されます。 しかし、このスタイル付けの障壁は、ページが実際にそうすることを望む場合にも、 ページがそのコンポーネントと相互作用することを難しくします。

この仕様は、::part() 疑似要素を定義します。 これは、作者が shadow tree 内で、意図的に公開された特定の要素を、外部ページのコンテキストからスタイル付けできるようにします。 custom properties と組み合わせることで、 外部ページは特定の値 (テーマカラーなど)を コンポーネントへ渡し、コンポーネントがそれを自由に扱えるようにできます。 これらの疑似要素により、コンポーネントと外部ページは 安全かつ強力な方法で相互作用でき、 すべての制御を手放すことなく カプセル化を維持できます。

テスト

shadow parts の一般的なテスト


1.1. 動機

カスタム要素が完全に有用で、組み込み要素と同等の能力を持つためには、 その一部を外部からスタイル付けできるべきです。 外部から正確に何をスタイル付けできるかは、要素の作者が制御すべきです。 また、カスタム要素がスタイル付けのための安定した「API」を提示できるべきです。 つまり、カスタム要素の一部をスタイル付けするために使われるセレクターは、 要素の内部詳細を公開したり、その知識を要求したりすべきではありません。 カスタム要素の作者は、セレクターを変更せずに 要素の内部詳細を変更できるべきです。

shadow tree 内をスタイル付けするために以前提案されていた方法である >>> コンビネーターは、 それ自体のためには強力すぎることが判明しました。 それはコンポーネントの内部構造を過度に詳しく調査できるように公開し、 Shadow DOM を使用することで得られるカプセル化の利点の一部を損なっていました。 このため、 またその他のパフォーマンス関連の理由から、 >>> コンビネーターは最終的に削除されました。

これにより、shadow tree 内をスタイル付けする唯一の方法として custom properties を使用することが残されました: コンポーネントは、その内部をスタイル付けするために特定の custom properties を使用することを通知し、 外部ページは必要に応じて、それらのプロパティを shadow host 上に設定できます。 これにより、継承が値を必要な場所まで押し下げます。 これは多くの単純なテーマ設定のユースケースで非常によく機能します。

しかし、これがうまくいかない場合もあります。 コンポーネントが、その shadow tree 内の何かに対する任意のスタイル付けを許可したい場合、 それを行う唯一の方法は、制御を許可したい CSS プロパティ 1 つにつき 1 つ、 何百もの custom properties を定義することです。 これは、使いやすさとパフォーマンスの両方の理由から、 明らかに非現実的です。 作者が、:hover のような疑似クラスに基づいて コンポーネントを異なる方法でスタイル付けしたい場合、 状況はさらに悪化します。 コンポーネントは、各疑似クラス (および :hover:focus のような各組み合わせ)ごとに 使用する custom properties を複製する必要があり、 組み合わせ爆発が生じます。 これにより、使いやすさとパフォーマンスの問題はさらに悪化します。

この場合をはるかにエレガントかつ高性能に処理するために、::part() を導入します。 すべてを custom property 名に詰め込むのではなく、 本来そうであるべきように、 機能はセレクターとスタイル規則の構文の中に存在します。 これは、コンポーネント作者と コンポーネント利用者の両方にとってはるかに使いやすく、 パフォーマンスもはるかに良くなるはずであり、 より良いカプセル化/API サーフェスを可能にします。

::part() は、理論的に新しい能力をまったく提供しないことに注意することが重要です。 これは >>> コンビネーターの焼き直しではなく、 作者がすでに custom properties で行えることのための、 より便利で一貫した構文にすぎません。 要素の明示的に「公開された」部分 (part element map)を、 たまたま含んでいるだけのサブパートから分離することで、 カプセル化にも役立ちます。 作者は、偶発的な過剰スタイル付けを恐れずに ::part() を使用できます。

2. Shadow Element の公開:

shadow tree 内の要素は、 part および exportparts 属性を使用して、 tree の外部のスタイルシートによるスタイル付けのためにエクスポートできます。

各要素は、トークンの ordered set である part name list を持ちます。

各要素は、転送される inner part のための string と、 それが公開される名前を与える string を含む tupleslist である forwarded part name list を持ちます。

shadow root は、キーが strings であり、値が要素の ordered sets である part element map を持つものと考えることができます。

part element map は、この仕様におけるスタイル計算アルゴリズムの一部としてのみ 記述されます。 これは DOM を通じて公開されません。 その計算は高価である可能性があり、 公開すると closed shadow roots 内の要素へのアクセスを可能にし得るためです。

Part element maps は、要素の追加および削除、 ならびに DOM 内の要素の part name lists および forwarded part name lists の変更の影響を受けます。

shadow root outerRoot part element map を計算するには:
  1. outerRoot 内の各 descendant el について:

    1. elpart name list 内の各 name について、elouterRootpart element map[name] に append します。

    2. el 自体が shadow host である場合、 innerRoot をその shadow root とします。

    3. innerRootpart element map計算します

    4. elforwarded part name list 内の 各 innerName/outerName について:

      1. innerName が ident である場合:

        1. innerPartsinnerRootpart element map[innerName] とします

        2. innerParts 内の要素を outerRootpart element map[outerName] に Append します

      2. innerName が pseudo-element 名である場合:

        1. その名前を持つ innerRoot の pseudo-element(s) を outerRootpart element map[outerName] に Append します。

2.1. Shadow Element の命名: part 属性

shadow tree 内の任意の要素は、part 属性を持つことができます。 これは、要素を shadow tree の外部へ公開するために使用されます。

テスト

part 属性は、この要素の part 名を表す、空白区切りのトークンのリストとして構文解析されます。

注記: 1 つの part に複数の名前を与えてもかまいません。 "part name" は、id や tagname ではなく、 class に似たものと考えるべきです。

<style>
  c-e::part(textspan) { color: red; }
</style>

<template id="c-e-template">
  <span part="textspan">このテキストは赤になります</span>
</template>
<c-e></c-e>
<script>
  // テンプレートをカスタム要素 c-e として追加する
  ...
</script>

2.2. Shadow Element の転送: exportparts 属性

shadow tree 内の任意の要素は、exportparts 属性を持つことができます。 その要素が shadow host である場合、 これは、shadow tree 内の host からの part を、この shadow tree の外部の規則で スタイル付けできるようにするために使用されます (それらが host と同じ tree 内の要素であり、 part 属性によって名前付けされているかのように)。
テスト

exportparts 属性は、part mappings のコンマ区切りのリストとして構文解析されます。 各 part mapping は次のいずれかです:

innerIdent : outerIdent

innerIdent/outerIdent を el の forwarded part name list に追加します。

ident

ident/ident を el の forwarded part name list に追加します。

注記: これは ident : ident の省略形です。

::ident : outerIdent

::identfully styleable pseudo-element の名前である場合、 ::ident/outerIdent を el の forward part name list に追加します。 そうでなければ、何もしません。

その他すべて

エラー回復 / 将来の互換性のために無視されます。

注記: sub-part を複数の名前へ map してもかまいません。

<style>
  c-e::part(textspan) { color: red; }
</style>

<template id="c-e-outer-template">
  <c-e-inner exportparts="innerspan: textspan"></c-e-inner>
</template>

<template id="c-e-inner-template">
  <span part="innerspan">
    このテキストは赤になります。なぜなら、包含する shadow
    host が innerspan を "textspan" として document へ転送し、
    document のスタイルがそれに一致するためです。
  </span>
  <span part="textspan">
    このテキストは赤になりません。なぜなら、document スタイル内の textspan は、
    inner custom element の内側にある part に対しては、
    それが転送されていない場合、一致できないためです。
  </span>
</template>

<c-e></c-e>
<script>
  // テンプレートをカスタム要素 c-e-inner, c-e-outer として追加する
  ...
</script>
たとえば、fully styleable pseudo-element は、 それが含まれるコンポーネントに対して ::part() のように見せかけるために、 exportparts 属性内で使用できます:
<template id=custom-element-template>
  <p exportparts="::before : preceding-text, ::after : following-text">
    Main text.
</template>

そのテンプレートを使用する要素は、 x-component::part(preceding-text) のようなセレクターを使用して、その shadow 内の p::before 疑似要素を対象にできます。 そのため、コンポーネントの利用者は、 preceding text が疑似要素として実装されていることを知る必要がありません。

3. Shadow Element の選択: ::part() 疑似要素

::part() 疑似要素は、 part 属性を介して公開された要素を選択できるようにします。 構文は次のとおりです:

::part() = ::part( <ident>+ )
テスト

::part() 疑似要素は、 originating elementshadow host である場合にのみ、何かに一致します。

たとえば、 part="label" によってスタイル付けのために公開された "label" 要素を含むカスタムボタンがある場合、 x-button::part(label) でそれを選択できます。
Part 名は class と似たように動作します: 複数の要素が同じ part 名を持つことができ、 単一の要素が複数の part 名を持つこともできます。

tabstrip コントロールは、 part="tab" を持つ複数の要素を持つ場合があり、 それらはすべて ::part(tab) によって選択されます。

一度に 1 つの tab だけが active である場合、 part="tab active" で特別に示すことができ、その後 ::part(tab active)(または順序は重要でないため ::part(active tab))によって選択できます。

::part() 疑似要素は fully styleable pseudo-element です。 originating elementshadow rootpart element map が、指定された <ident>contains する場合、 ::part() はその ident に対応付けられた要素を表します。 複数の ident が与えられ、part element map がそれらすべてを含む場合、 それぞれの ident に対応付けられた要素の積集合を表します。 そうでなければ、何にも一致しません。

::part() 疑似要素は、 originating element の shadow tree 内での位置に従って継承します。

たとえば、x-panel::part(confirm-button)::part(label) は決して何にも一致しません。 これは、そうすると意図された以上の構造情報を公開してしまうためです。

<x-panel> の内部 confirm button が、button の内部 part を panel 自身の part element map へ転送するために part="label => confirm-label" のようなものを使用していた場合、 x-panel::part(confirm-label) のようなセレクターは、 他の label を無視して、 その 1 つの button の label だけを選択します。

4. Element インターフェイスへの拡張

partial interface Element {
  [SameObject, PutForwards=value] readonly attribute DOMTokenList part;
};
テスト

part 属性の getter は、関連付けられた要素がコンテキストオブジェクトであり、 関連付けられた属性のローカル名が part である DOMTokenList オブジェクトを返さなければなりません。 この特定の DOMTokenList オブジェクトのトークン集合は、その要素の parts とも呼ばれます。

これを DOM 仕様の superglobal として定義します。 [w3c/csswg-drafts Issue #3424]

5. 構文解析のためのマイクロ構文

5.1. part mappings を構文解析するための規則

妥当な part mapping は、 U+003A COLON 文字で区切られ、 U+003A COLON の前後に任意個数の空白文字を伴う トークンの tuple です。 トークンは U+003A COLON または U+002C COMMA 文字を含んではなりません。

part mapping を構文解析するための規則は次のとおりです:

  1. input を、構文解析される文字列とします。

  2. position を、input 内へのポインターとし、初期状態では文字列の先頭を指すものとします。

  3. 空白文字である code point の列を 収集します

  4. 空白文字または U+003A COLON 文字でない code point の列を 収集しfirst token をその結果とします。

  5. first token が空である場合、error を返します。

  6. 空白文字である code point の列を 収集します

  7. input の終端に達している場合、tuple (first token, first token) を返します

  8. position の文字が U+003A COLON 文字でない場合、error を返します。

  9. U+003A COLON 文字を消費します。

  10. 空白文字である code point の列を 収集します

  11. 空白文字または U+003A COLON 文字でない code point の列を 収集します。 そして second token をその結果とします。

  12. second token が空である場合、error を返します。

  13. 空白文字である code point の列を 収集します

  14. positioninput の終端を過ぎていない場合、error を返します。

  15. tuple (first token, second token) を返します。

5.2. part mappings のリストを構文解析するための規則

妥当な part mappings のリスト は、U+002C COMMA 文字で区切られ、 U+002C COMMA の前後に任意個数の空白文字を伴う、 妥当な part mappings の個数です

part mappings のリストを構文解析するための規則は次のとおりです:

  1. input を、構文解析される文字列とします。

  2. 文字列 input をコンマで分割しますunparsed mappings を、その結果の文字列のリストとします。

  3. mappings を、トークンの tuples の 初期状態で空の list とします。 この list がこのアルゴリズムの結果になります。

  4. unparsed mappings 内の各文字列 unparsed mapping について、 次のサブ手順を実行します:

    1. unparsed mapping が空であるか、空白文字のみを含む場合、 ループの次の反復へ続行します。

    2. mapping を、 part mappings を構文解析するための規則を用いて unparsed mapping を構文解析した結果とします。

    3. mapping が error である場合、ループの次の反復へ続行します。 これにより、クライアントは理解されない新しい構文をスキップできます。

    4. mappingmappings に追加します。

6. プライバシーに関する考慮事項

この仕様は、ページ上の要素のスタイル付けを対象にする新しい方法を定義しますが、 それらはすでに他の方法で完全にスタイル付け可能です。 そのため、新しいプライバシー上の考慮事項は導入しません。

7. セキュリティに関する考慮事項

shadow trees は意図的にセキュリティ境界ではなく、 ページ作者のための単なる利便性であるため、 この方法でそれらをセレクターに公開しても、新しいセキュリティ上の考慮事項は導入されません。

8. 変更点

2018年11月15日の First Public Working Draft 以降の変更点

適合性

文書の規約

適合性要件は、 記述的な表明と RFC 2119 の用語の組み合わせで表現されます。規範的部分におけるキーワード “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, および “OPTIONAL” は、 RFC 2119 で説明されているとおりに解釈されます。 ただし、読みやすさのため、この仕様ではこれらの語はすべて大文字では 表示されません。

この仕様のすべてのテキストは規範的です。ただし、 非規範的であることが明示的に示された節、例、および注記を除きます。 [RFC2119]

この仕様における例は、“for example” という語で導入されるか、 class="example" を用いて規範的なテキストから分離され、 次のように示されます:

これは参考情報としての例の一例です。

参考情報としての注記は “Note” という語で始まり、 class="note" を用いて規範的なテキストから分離され、 次のように示されます:

注記、これは参考情報としての注記です。

勧告は、特別な注意を引くようにスタイル付けされた規範的な節であり、 <strong class="advisement"> を用いて他の規範的テキストから分離されます。 次のようになります: UA はアクセシブルな代替手段を提供しなければなりません。

テスト

この仕様の内容に関するテストは、 このような “Tests” ブロックに記録される場合があります。 そのようなブロックはいずれも非規範的です。


適合クラス

この仕様への適合性は、 3 つの適合クラスについて定義されます:

style sheet
CSS style sheet
renderer
style sheet の意味を解釈し、それらを使用する文書をレンダリングする UA
authoring tool
style sheet を書く UA

style sheet は、このモジュールで定義された構文を使用するすべての文が、 汎用 CSS 文法およびこのモジュールで定義される各 機能の個別文法に従って妥当である場合、 この仕様に適合します。

renderer は、 適切な仕様で定義されているとおりに style sheet を解釈することに加えて、 この仕様で定義されるすべての機能を正しく構文解析し、 それに応じて文書をレンダリングすることでサポートする場合、 この仕様に適合します。ただし、 デバイスの制限により UA が文書を正しくレンダリングできないことは、 その UA を非適合にするものではありません。(たとえば、UA は モノクロモニター上で色をレンダリングする必要はありません。)

authoring tool は、 汎用 CSS 文法およびこのモジュール内の各機能の個別文法に従って 構文的に正しい style sheet を書き、 このモジュールで説明される style sheet のその他すべての適合性要件を 満たす場合、この仕様に適合します。

部分的な実装

作者が前方互換な構文解析規則を利用してフォールバック値を 割り当てられるようにするため、CSS renderer は、利用可能なサポートレベルを持たない at-rule、プロパティ、プロパティ値、キーワード、 およびその他の構文構造を、無効として扱い(必要に応じて 無視)しなければなりません。 特に、ユーザーエージェントは、単一の複数値プロパティ宣言内で、 サポートされていない構成値を選択的に無視し、 サポートされている値を尊重してはなりません。いずれかの値が無効と見なされる場合 (サポートされていない値はそのように扱われなければならないため)、CSS は宣言全体を 無視することを要求します。

不安定な機能および 独自機能の実装

将来の安定した CSS 機能との衝突を避けるため、 CSSWG は CSS の 不安定な機能および独自拡張の実装について、 ベストプラクティスに従うことを推奨します。

非実験的な実装

仕様が Candidate Recommendation 段階に達すると、 非実験的な実装が可能になり、実装者は、 仕様に従って正しく実装されていることを示せる CR レベルの機能について、 接頭辞なしの実装をリリースすべきです。

実装間での CSS の相互運用性を確立し維持するため、 CSS Working Group は、非実験的な CSS renderer が、 CSS 機能の接頭辞なし実装をリリースする前に、 実装報告(必要な場合は、その実装報告に使用した テストケース)を W3C に提出することを求めます。W3C に提出されたテストケースは、 CSS Working Group によるレビューと修正の対象となります。

テストケースおよび実装報告の提出に関する詳細情報は、 CSS Working Group の Web サイト https://www.w3.org/Style/CSS/Test/ で見つけることができます。 質問は public-css-testsuite@w3.org メーリング リストに送ってください。

索引

この仕様で定義される用語

参照により定義される用語

参考文献

規範的参考文献

[CSS-PSEUDO-4]
Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. 27 June 2025. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 12 March 2024. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS-VARIABLES-1]
Tab Atkins Jr.. CSS Custom Properties for Cascading Variables Module Level 1. 16 June 2022. CR. URL: https://www.w3.org/TR/css-variables-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 11 November 2022. WD. URL: https://www.w3.org/TR/selectors-4/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

IDL 索引

partial interface Element {
  [SameObject, PutForwards=value] readonly attribute DOMTokenList part;
};

課題索引

これを DOM 仕様の superglobal として定義します。 [w3c/csswg-drafts Issue #3424]