PolymerはDOMテンプレートとShadow DOM APIをサポートしています。Custom ElementにDOMテンプレートを利用すると、Polymerはあなたがエレメントに作成したテンプレートの内容をコピーします。

例:

Plunkerで動作を確認

custom-element.html

<!-- Import polymer-element -->
<link rel="import" 
href="https://polygit.org/polymer+:2.0-preview/webcomponentsjs+:v1/shadydom+webcomponents+:master/sh
adycss+webcomponents+:master/custom-elements+webcomponents+:master/components/polymer/polymer-elemen
t.html">

<!-- Create a template for the custom element -->
<dom-module id='custom-element'>
  <template>
    <h1>Heading!</h1>
    <p>We are elements in custom-element's local DOM.</p>
  </template>

  <!-- Register the element -->
  <script>
    class CustomElement extends Polymer.Element {
      static get is() {
        return "custom-element";
      }
    }
    customElements.define(CustomElement.is, CustomElement);
  </script>
</dom-module>

index.html

<!-- Load the polyfills -->
<script 
src="https://polygit.org/polymer+:2.0-preview/webcomponentsjs+:v1/shadydom+webcomponents+:master/sha
dycss+webcomponents+:master/custom-elements+webcomponents+:master/components/webcomponentsjs/webcomp
onents-loader.js"></script>

<!-- Load the custom element -->
<link rel="import" href="custom-element.html">
<!-- Drop the custom element on the page -->
<custom-element></custom-element>

テンプレート内のHTMLエレメントは、Custom ElementのShadow DOMの子になります。Shadow DOMは、カプセル化のメカニズムを提供するので、Shadow DOMの内部のエレメントがShadow DOM外部のセレクタにマッチすることはありません。

同様に、Shadow DOM内部のスタイルルールについても、Shadow DOM外部のエレメントにリークして影響を与えることはありません。

Shadow DOMは、Custom Elementsに対するスタイルルールのカプセル化を可能にします。エレメントのスコープ外にスタイルが適用されてしまう心配をせず、フォントやテキストカラー、クラスなどのスタイル情報をエレメントに自由に定義できます。

例:

Plunkerで動作を確認

x-foo.html

<dom-module id='x-foo'>
  <template>
    <!-- Encapsulated, element-level stylesheet -->
    <style>
      p {
        color: green;
      }
      .myclass {
        color: red;
      }
    </style>
    <p>I'm a shadow DOM child element of x-foo.</p>
    <p class="myclass">So am I.</p>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">
<!-- Document-level stylesheet -->
<style>
  .myclass {
    color: blue;
  }
</style>
<x-foo></x-foo>
<!-- The following paragraph uses the document-level stylesheet. -->
<p class="myclass">I have nothing to do with x-foo. Because of encapsulation, x-foo's styles won't 
leak to me.</p>

PolymerにおけるShadow DOMの詳細な解説は、Shadow DOMのコンセプトを参照してください。

Shadow DOM v1のAPIの詳細については、Shadow DOM v1: Self-Contained Web Componentsを参照してください。

HTMLドキュメントで使用された場合、エレメントはその親エレメントに適用される全てのスタイル情報を継承します。:

Plunkerで動作を確認

x-foo.html

<dom-module id='x-foo'>
  <template>
    <div>
      I inherit styles from x-foo's parent in the light DOM.
      I'm also sans-serif and blue.
    </div>
  </template>
</dom-module>

index.html

<link rel="import" href="x-foo.html">
<!-- Document-level stylesheet -->
<style>
  p {
    font-family: sans-serif;
    color: blue;
  }
</style>

<!-- This paragraph uses document-level styles: -->
<p>I'm sans-serif and blue.</p>

<!-- And the text within x-foo inherits style from the paragraph element: -->
<p><x-foo></x-foo></p>

Shadow DOMの内側で宣言されたスタイルは、その外側で宣言されたスタイルを上書きします:

Plunkerで動作を確認

x-foo.html

<dom-module id='x-foo'>
  <template>
    <!-- Encapsulated, element-level stylesheet -->
    <style>
      p {
        font-family: sans-serif;
        color: green;
      }
    </style>
    <p>I'm green.</p>
  </template>
</dom-module>

index.html

<link rel="import" href="x-foo.html">
<!-- Document-level stylesheet -->
<style>
  p {
    font-family: sans-serif;
    color: blue;
  }
</style>
<p>I'm blue.</p>
<p><x-foo></x-foo></p>

Shadow DOMが追加されたエレメントは、ホストと呼ばれます。ホストにスタイルを設定するには、セレクタ:hostを使用してください。

ホストエレメントの継承可能なプロパティは、Shadow Treeを下って継承され、Shadowの子にも適用されます。

Plunkerで動作を確認

x-foo.html

<dom-module id='x-foo'>
  <template>
    <!-- Encapsulated, element-level stylesheet -->
    <style>
      :host {
        font-family: sans-serif;
        color: green;
        display: block;
        border: 1px solid;
      }
    </style>
    <p>I'm green.</p>
    <div>I'm green too.</div>
    <span>We're all green...</span>
  </template>
</dom-module>

index.html

<link rel="import" href="x-foo.html">
<x-foo></x-foo>

また、ホストエレメントを外部からスタイリングすることもできます。例えば、エレメント型セレクタを使用したとします。:

Plunkerで動作を確認

x-foo {
	background-color: blue;
}

CSSセレクタを使用することで、ホストのスタイルを設定するタイミングや方法を指定できます。このコードサンプルでは、

  • セレクタ:hostは、どんな<x-foo>エレメントにもマッチします
  • セレクタ:host(.blue)は、classがblue<x-foo>エレメントにマッチします
  • セレクタ:host(.red)は、classがred<x-foo>エレメントにマッチします
  • セレクタ:host(:hover)は、<x-foo>エレメントにマウスがホバーした時にマッチします

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <style>
      :host { font-family: sans-serif; }
      :host(.blue) {color: blue;}
      :host(.red) {color: red;}
      :host(:hover) {color: green;}
    </style>
    <p>Hi, from x-foo!</p>
  </template>
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo class="blue"></x-foo>
<x-foo class="red"></x-foo>

セレクタ:hostに続けて、子孫セレクタがShadow Tree内のエレメントにマッチします。次の例では、CSSセレクタがShadow Tree内の全てのpエレメントへホストがクラスwarningを持っているか問い合わせます。:

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <style>
      :host(.warning) p {
        color: red;
      }
    </style>
    <p>Make this text red if x-foo has class "warning", and black otherwise.</p>
  </template>
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo class="warning"></x-foo>
<x-foo></x-foo>

Shadow Tree内部ルールがShadow Tree外部のエレメントに影響を与える可能性のあるインスタンスは二つあり、:hostセレクタによるスタイリングはその内の一つです。もう一つのインスタンスは、次のセクションで紹介する::slotted()構文を使用した、割り当てられた子(distributed children)へのスタイルルールの適用です。詳細については、[Composition and slots in Eric Bidelman's article on shadow DOM](https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom#composition_sl ot)を参照してください。

実行時に割り当てられるエレメントのテンプレートにslotsを作成することができます。スロットに関する詳細な情報は、ドキュメント中のshadow DOM and compositionを参照してだい。

スロットに組み込まれるコンテンツの基本的な構文は、次のようになります。:

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <h1>
      <slot name="title"></slot>
    </h1>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo>
  <span slot="title">I'm a heading!</span>
</x-foo>

スロットされたコンテンツにスタイルを適用するには、::slotted()構文を使用します。

注意: Shady CSSのスコープに関するShimの制限内で ブラウザ間で一貫した動作を確保するには、::slotted(.classname)の左側にセレクタを追加します。(例:p ::slotted(.classname)

::slotted(*)はスロットされた全てのコンテンツを選択します。:

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <style>
      p ::slotted(*), h1 ::slotted(*) {
        font-family: sans-serif;
        color:green;
      }
    </style>
    <h1>
      <div><slot name='heading1'></slot></div>
    </h1>
    <p>
      <slot name='para'></slot>
    </p>
  </template>
	...
</dom-module>

index.html

<link rel="import" href="x-foo.html">
<x-foo>
  <div slot="heading1">Heading 1. I'm green.</div>
  <div slot="para">Paragraph text. I'm green too.</div>
</x-foo>

Plunkerで動作を確認

エレメントの型で選択することもできます:

x-foo.html

<dom-module id="x-foo">
  <template>
    <style>
      h1 ::slotted(h1) {
        font-family: sans-serif;
        color: green;
      }
      p ::slotted(p) {
        font-family: sans-serif;
        color: blue;
      }
    </style>
    <h1><slot name='heading1'></slot></h1>
    <p><slot name='para'></slot></p>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo>
  <h1 slot="heading1">Heading 1. I'm green.</h1>
  <p slot="para">Paragraph text. I'm blue.</p>
</x-foo>

クラスで選択することもできます:

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <style>
      p ::slotted(.green) {
        color:green;
      }
    </style>
    <p>
      <slot name='para1'></slot>
    </p>
    <p>
      <slot name='para2'></slot>
    </p>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo>
  <div slot="para1" class="green">I'm green!</div>
  <div slot="para1">I'm not green.</div>
  <div slot="para2" class="green">I'm green too.</div>
  <div slot="para2">I'm not green.</div>
</x-foo>

スロットの名前で選択することもできます:

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <style>
      p ::slotted([slot=para1]) {
        color:green;
      }
    </style>
    <p>
      <slot name='para1'></slot>
    </p>
    <p>
      <slot name='para2'></slot>
    </p>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo>
  <div slot="para1">I'm green.</div>
  <div slot="para2">I'm not green.</div>
</x-foo>

FOUC(スタイルが適用されていないコンテンツによるちらつき)を避けるために、Custom Elementsが定義される前にスタイルを適用したい場合があるかもしれません。(つまり、ブラウザがクラスの定義をマークアップタグにアタッチする前)。仮にスタイルを適用しなければ、ブラウザは最初の描画でエレメントに一切スタイルを適用しない可能性があります。通常、あなたはエレメントの定義がロードされる間にもアプリケーションのレイアウトが表示されるようにトップレベルのいくつかのエレメントにスタイルを適用したいかもしれません。

定義が完了したターゲットエレメントに対しては擬似クラスセレクタ:definedが使えます。しかしCustom Elementsのポリフィルはこのセレクタをサポートしていません。

ポリフィルがうまく動作するための対処法として、マークアップでエレメントにunresolved属性を追加してください。例えば:

<my-element unresolved></my-element>

そうすれば、未解決(unresolved)のエレメントであってもスタイルが適用されます。例えば:

<style>
  my-element[unresolved] {
    height: 45px;
    text-align: center;
    ...
  }
</style>

最終的に、readyコールバック内でunresolved属性を取り除くようにします。:

class myElement extends Polymer.Element(){
  ...
  ready(){
    super.ready();
    this.removeAttribute('unresolved');
    ...
  }
  ...
}

スタイルを共有するのに望ましい方法は、スタイルモジュールを使うことです。スタイルモジュールにスタイルをパッケージ化し、エレメント間でそれらを共有することができます。

スタイルモジュールを作成するには、スタイルのブロックを<dom-module>エレメントと<template>エレメントで以下のようにラップします。:

<dom-module id="my-style-module">
  <template>
    <style>
      <!-- Styles to share go here! -->
    </style>
  </template>
</dom-module>

これらスタイルを利用してエレメントを作成するには、スタイルブロックの開始タグでスタイルモジュールをインクルードします。:

<dom-module id="new-element">
  <template>
    <style include="my-style-module">
      <!-- Any additional styles go here -->
    </style>
    <!-- The rest of your element template goes here -->
  </template>
</dom-module>

スタイルモジュールを独自のHTMLファイルにパッケージ化したいと考えるかもしれません。その場合は、スタイルを利用するエレメントにおいてHTMLファイルをインポートする必要があります。

例:

Plunkerで動作を確認

my-colors.html

<!-- Define some custom properties in a style module. -->
<dom-module id='my-colors'>
  <template>
    <style>
      p.red {
        color: red;
      }
      p.green {
        color: green;
      }
      p.blue {
        color: blue;
      }
    </style>
  </template>
</dom-module>

x-foo.html

<!-- Import the styles from the style module my-colors -->
<link rel="import" href="my-colors.html">
<dom-module id="x-foo">
  <template>
    <!-- Include the imported styles from my-colors -->
    <style include="my-colors"></style>
    <p class="red">I wanna be red</p>
    <p class="green">I wanna be green</p>
    <p class="blue">I wanna be blue</p>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo></x-foo>

非推奨の機能。この実験的な機能は、現在、スタイルモジュールに代替され、その利用は推奨されていません。現在もサポートされていますが、そのサポートは今後削除される見込みです。

Polymer includes an experimental feature to support loading external stylesheets that will be applied to the local DOM of an element. This is typically convenient for developers who like to separate styles, share common styles between elements, or use style pre-processing tools. The syntax is slightly different from how stylesheets are typically loaded, as the feature leverages HTML Imports (or the HTML Imports polyfill, where appropriate) to load the stylesheet text such that it may be properly shimmed and/or injected as an inline style.

To include a remote stylesheet that applies to your Polymer element's local DOM, place a special HTML import <link> tag with type="css" in your <dom-module> that refers to the external stylesheet to load.

For example:

Plunkerで動作を確認

style.css

.red { color: red; }
.green { color: green; }
.blue { color: blue; }

x-foo.html

<!-- Include the styles, and use them in x-foo. -->
<dom-module id="x-foo">
  <link rel="import" type="css" href="style.css">
  <template>
    <p class="red">I wanna be red</p>
    <p class="green">I wanna be green</p>
    <p class="blue">I wanna be blue</p>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">

<x-foo></x-foo>

最新のShadow DOM v1仕様を実装しているブラウザは、スタイルを自動でカプセル化し、スタイルが定義されたエレメントの内部にスコープします。

一部のブラウザでは、Shadow DOM v1仕様が実装されていません。あなたのアプリやエレメントをこれらのブラウザ上で正常に表示されるようにするには、custom-styleを使ってスタイル情報がエレメントのローカルDOM内にリークしないようにする必要があります。

custom-styleはShadow DOM v1仕様を実装していないブラウザであっても、ポリフィルを有効にすることでアプリケーションやエレメントのスタイルが、これらの仕様に沿って期待した通りに動作するようにしてくれます。

定義したスタイルをすべてのブラウザ上でShadow DOM v1仕様に従って動作するようにするには、ドキュメントレベルのスタイルを定義する際にcustom-styleを使用します。custom-stylePolymer.Elementに含まれておらず、個別にインポートする必要があります。custom-styleはレガシーな{code5}polymer.html{/code5}インポートには含まれています。

注意:custom-styleはメインドキュメントのスタイルの定義だけに使用してください。エレメントのローカルDOMのスタイルを定義するには単に<style>ブロックを使用します。

最初のサンプルコードは、Shadow DOM v1仕様を実装していないブラウザ上で、pエレメントに適用したスタイルがパラグラフBにリークしている様子を示しています。二番目のコードサンプルでは、​​custom-styleでスタイルブロックをラップすることでリークを防いでいます。

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <p>
      Paragraph B: I am in the shadow DOM of x-foo.
      If your browser implements the Shadow DOM v1 specs,
      I am black; otherwise, I'm red.
    </p>
  </template>
  ...
</dom-module>

index.html

<link rel="import" href="x-foo.html">
<style>
  p {
    color: red;
  }
</style>
<p>Paragraph A: I am in the main document. I am red.</p>

<x-foo></x-foo>

Plunkerで動作を確認

x-foo.html

<dom-module id="x-foo">
  <template>
    <p>Paragraph B: I am in the local DOM of x-foo. I am black on all browsers.</p>
  </template>
  ...
</dom-module>

index.html

<!-- import custom-style -->
<link rel="import" href="/bower_components/polymer/lib/elements/custom-style.html">
<link rel="import" href="x-foo.html">

<custom-style>
  <style>
    p {
      color: red;
    }
  </style>
</custom-style>
<p>Paragraph A: I am in the main DOM. I am red.</p>
<x-foo></x-foo>

custom-styleの構文は変更されました。Polymer 2.xでは、<custom-style>はラッパーエレメントとなりました。ハイブリッド構文を使用することで、Polymer 1.xと他のバージョンとの互換性を担保することができます。

Polymer 2.x

<custom-style>
  <style>
    p {
		...
    }
  </style>
</custom-style>

ハイブリッド (1.xと2.xで相互に互換性がある)

<custom-style>
  <style is="custom-style">
    p {
		...
    }
  </style>
</custom-style>

Polymer 1.x

<style is="custom-style">
  p {
	  ...
  }
</style>