::slottedについて

## はじめに
 
::slottedとは、web componentsで作ったcustom elementsのslot内部に入る要素に対してスタイルを適用するものです。
shadow DOM内で使われる時のみ::slottedは機能します。

実際使ってみて、よくわからなくて困った部分がわりとあったのでまとめておきます。

## ::slottedの使い方

使い方について例を出しつつ説明します。

### ::slotted(*), ::slotted(selector) 

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="smspp" data-slug-hash="mYbarR" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="::slotted(*), ::slotted(selector)">
  <span>See the Pen <a href="https://codepen.io/smspp/pen/mYbarR/">
  ::slotted(*), ::slotted(selector)</a> by こは (<a href="https://codepen.io/smspp">@smspp</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>  
  
`::slotted(*)`と、()に*でslot内に入る全てのセレクタに対してスタイルを適用します。
`::slotted(span)`と、()になんらかのセレクタ指定でそのセレクタのみにスタイルを適用します。クラス名でも属性でも指定できます。

### ::slotted(*:hover)

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="smspp" data-slug-hash="EzYGpa" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="::slotted(*:hover)">
  <span>See the Pen <a href="https://codepen.io/smspp/pen/EzYGpa/">
  ::slotted(*:hover)</a> by こは (<a href="https://codepen.io/smspp">@smspp</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
`:focus`や`:hover`などslot内の要素に擬似要素使いたい場合は、`::slotted(*:hover)`のように()の中で指定します。
もちろん特定のセレクタに対しての指定も可能です。(`::slotted(span:hover)`のようになります)

### ::slotted(*)::after
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="smspp" data-slug-hash="XwroOJ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="::slotted(*)::after">
  <span>See the Pen <a href="https://codepen.io/smspp/pen/XwroOJ/">
  ::slotted(*)::after</a> by こは (<a href="https://codepen.io/smspp">@smspp</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

擬似要素使う場合は()の中に入れると先述しましたが、`::before`や`::after`、`::placeholder`など生成される擬似要素に関しては、`::slotted(*)::after`のように()の後ろで指定します。

経緯は一応こちらから確認できます(参考でも挙げています)↓
[Support for pseudo elements with ::slotted() selectors](https://github.com/w3c/webcomponents/issues/655)

## ::slottedが効かない時確認すること

::slotted効かないなぁ・・・と困ったシーンが何度もありました。
(確認し直してみると、しょうもないことが原因で効いてないことがほとんどでしたが)

困った時は下記を確認してみるといいかもしれません。


### 1.custom elements内に < slot >があるか

そもそもですが、custom elements内に`<slot>`がないと外部からの要素を適用できません。
`<slot>`があるか確認してみてください。

これについて、多分jsでcustom elements作る場合は特に困らない点だと思いますが、[vue-web-component-wrapper](https://github.com/vuejs/vue-web-component-wrapper)を使って作る場合に注意が必要かなと思います。
vueの仕様上、レンダリングされるタイミングで`<slot>`が消えちゃうんです。
(`<slot>`が消えて、`<slot>`があった部分にcustom elements内に記述した要素が入ります)

`$nextTick`を使ってこれに対処する方法あります↓
[How to properly use slot inside of vue js web component and apply styles](https://stackoverflow.com/questions/55169976/how-to-properly-use-slot-inside-of-vue-js-web-component-and-apply-styles/55712612#55712612)


### 2. custom elements内の直下の要素であるか

::slottedでスタイルを指定できるのは、custom elements内に入る直下の要素のみです。
下記のように、直下の子要素以降にスタイルを当てようとしても反映されません。


<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="smspp" data-slug-hash="mYbvRK" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="::slotted not work">
  <span>See the Pen <a href="https://codepen.io/smspp/pen/mYbvRK/">
  ::slotted not work</a> by こは (<a href="https://codepen.io/smspp">@smspp</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


### 3. shadow DOM内にstyleがあるか

custom elementsのスタイルはカプセル化されていて、外部に影響を与えないですし、外部からの影響も受けません。
(↑とは書きますが、cssのcustom propertyを使って外部からcustom elementsのスタイルを指定することもできます)

下記のように、shadow root内にスタイルがあればokです。
<img width="493" alt="スクリーンショット 2019-05-05 0.06.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275700/7cfe8ad9-bf28-b61b-1de3-2219b88107f2.png">



### 4. shadow DOM内のstyleに::slottedがあるか

はじめにでちらっと書きましたが、::slottedはshadow DOM内でしか機能しません。
つまり外部のスタイルシートに::slottedで指定してスタイル書いても動きません。

3.で確認したshadow DOM内のstyle内に書いているか、確認してみてください。


## 参考
[::slotted()
](https://developer.mozilla.org/ja/docs/Web/CSS/::slotted)[カスタム要素 v1: 再利用可能なウェブ コンポーネント](https://developers.google.com/web/fundamentals/web-components/customelements?hl=ja)
[Support for pseudo elements with ::slotted() selectors](https://github.com/w3c/webcomponents/issues/655)