この記事の内容についてのほとんどが対応ブラウザの少ないものなので、現段階でそのまま実際に使えるものではない。Polymerで使用されているCSSを初見でわりと理解できなかったかつての自分用メモです。Polymerの解説ではなくて仕様の整理なので注意。
scoped属性
これは直感的でわかりやすくて、HTML内部に直接style
要素を挿入してscoped
属性をつけるだけ。scoped
属性をもつ要素はフローコンテンツが許容される最初の子要素である必要があって、場合によってはそのstyle
要素をラップする親要素が必要になることもある。
<p>この文章にはスタイルが適用されません。</p>
<div>
<style scoped>
p { color: red; }
</style>
<p>この文章は文字が赤くなります。</p>
</div>
嫌がらせ以外で誰が使うんだろうかとおもっていたんだけども、後日CSSに死を!これはJSerの叫び!のスライドを見ていて、JavaScriptの中にスタイルを埋め込んでしまいたいときに使いたくなるということがわかった。
CSS Scoping Module
Polymerを使ってる人はすでに使っているはず。core-*
に含まれるCSSの:host
とか/deep/
がそれ。念のためすべて確認しておきます。
Scoped Styles
仕様書の順番通りにいくとまずは@scope
。これはscoped
属性と似たようなものなのだけれど、HTMLにそれほど干渉せずに指定できる。
<p>この文章にはスタイルが適用されません。</p>
<div>
<p>この文章は文字が赤くなります。</p>
</div>
このHTMLのdivでスコープを作りたいようなときには以下のようにCSSを記述する。
@scope div {
p { color: red; }
}
class
やid
つければいいだけなんじゃないかといわれるとそこまでなんだけど、そのスタイルを作成した作者のこのスタイルはそのコンテンツ内でしか使用しないですよという意図を明示することに意味があるのかもしれない。あとはCSSでネストされてると見通しがいいような気はするんだけど、いまどきCSS直接書く人なんていないだろうからそれがメリットになることはないよね。
それとこれは以下のようにも書けるということらしいんだけど、Issueになっていて色々な記法が提案されてるみたいだから、仕様だけみても今後どうなるかはわからないっぽい。
p:scope-context(div) {
color: red;
}
:scope
についてはよくわからない。CSS Selector 4にあるらしいので、気になる人は確認してみるといいと思う。確認してないけど、たぶんスコープをもっている要素を選択できるとかそんな感じじゃないかな。
これらはどうせ対応ブラウザはないだろうから覚えておく必要なんてない。そもそも対応したってScoped Stylesでわざわざこんなスコープ作る人なんていないんじゃないだろうか、少なくとも自分は絶対に使わない。
Shadow Encapsulation
これ以降の内容はShadow DOMだけでなくWeb Componentsについて理解していないと、何が書いてあるのかさっぱり理解できないかもしれない。
まずは:host
。これはshasow treeのコンテキストで評価されたときhost elementと一致する。言葉でみると何を言っているのかよくわからないんだけど、仕様書のサンプルをみるとそんなに難しいことを言っているわけでもないことがわかる。
<x-foo class="foo">
<"shadow tree">
<div class="foo">...</div>
</>
</x-foo>
コンポーネントがこのようなshadow treeを持つときには以下のようになる。
:host {} // <x-foo>を選択する
x-foo {} // 何とも一致しない
.foo {} // <div>要素のみを選択する
.foo:host {} // 何とも一致しない
:host(.foo) {} // <x-foo>を選択する
簡単に要約してしまうとshadow treeの外側にある<x-foo>
選択できないから:host
って書けばいいよ、ということ。
:host-context()
ではshadow treeの外の祖先の要素を指定することもできて、これは仕様いわくテーマで配色を変更したりするようなときに便利ということらしいです。
:shadow
はセレクタで使用するためのshadow treeのルートを選択するもので、shadow treeを複数持っていた場合にはすべてのshadow treeを選択する。つまり:host::shadow div
みたいなことをすると、そのホスト要素内にあるすべてのshadow tree内のdiv
を選択することになる。
::content
についても仕様のサンプルがわかりやすい。
<x-foo>
<div id="one" class="foo">...</div>
<div id="two">...</div>
<div id="three" class="foo">
<div id="four">...</div>
</div>
<"shadow tree">
<div id="five">...</div>
<div id="six">...</div>
<content select=".foo"></content>
</"shadow tree">
</x-foo>
::content div
とすると選択されるのは#one
, #three
, #four
になって、::content > div
とすると#four
のみが選択される。Polymerを使うならpolyfill-next-selector
。
/deep/
はshadow rootをまたいで要素を指定できる。
<x-foo>
<"shadow tree">
<div>
<span id="not-top">...</span>
</div>
<span id="top">...</span>
<x-bar>
<"shadow tree">
<span id="nested">...</span>
</>
</x-bar>
</>
</x-foo>
x-foo /deep/ span
とすると選択されるのは#top
, #not-top
, #nested
になる。最新のEDを確認してみると、/deep/
は>>>
になっていたのでそのうち変わるのかも。