最近の開発で同じコンポーネントを利用したいのに、ページによって文字色やサイズを変更しないといけないシチュエーションがありました。この時に上手く実装できるのか試行錯誤して自分的にしっくりきた方法を紹介させていただきます。
親コンポーネントからクラス名とスタイルを指定する
先に結論をお伝えすると、このような実装になります。
<p class={$$restProps.class || ''}>Child component</p>
<Child class="red" />
<style lang="scss">
:global(.red-text) {
color: red;
font-size: 16px;
}
</style>
なぜ:global()とクラス名をプロパティの合わせ技になったのか
Svelteで親コンポーエントから子コンポーネントのスタイルを指定する方法として、:global()を利用する方法、クラス名をプロパティにする方法、スタイル要素をプロパティにするなどいくつかあります。
どちらか一方の方法でも親コンポーネントから子コンポーネントのスタイル指定は実装可能なのですが、メリット・デメリットを考慮した結果合わせ技になりました。
それぞれのメリット・デメリットを表にまとめました。
| 方法 | メリット | デメリット |
|---|---|---|
| :global()を使う | 呼び出し元の親コンポーネントからスタイル指定できるので、コーンポーネント毎にスタイルが変化することが分かりやすい | コンポーネントごとに指定しても最後に呼び出されたスタイルに上書きされる1 |
| クラス名をプロパティにする | 親コンポーネントからクラス名を指示するだけで済む | 呼び出し元のコンポーネント毎にスタイルが変化することが分かりづらい |
| スタイル要素をプロパティにする | 呼び出し元の親コンポーネントからスタイル指定できるので、コンポーネント毎にスタイルが変化することが分かりやすい | プロパティが増えすぎると管理が面倒になる |
参考
比較した3つの実装例も参考に残しておきます。
コードを比較してみて、みなさんの環境でベストだと思う方法で実装してください。
:global()を使う方法
<p>Child component</p>
<div class="red-text">
<Child />
</div>
<style lang="scss">
.red-text :global(p) {
color: red;
font-size: 16px;
}
</style>
クラス名をプロパティにする
<p class={$$restProps.class || ''}>Child component</p>
<style lang="scss">
.red-text {
color: red;
font-size: 16px;
}
</style>
<Child class="red-text" />
スタイル要素をプロパティにする
<script lang="ts">
export let color: 'red' | 'blue'
export let fontSize: 'S' | 'M' | 'L'
</script
<p class={color} {fontSize}>Child component</p>
<style lang="scss">
.red {
color: red;
}
.blue {
color: blue;
}
.S {
font-size: 12px;
}
.M {
font-size: 16px;
}
.L {
font-size: 20px;
}
</style>
<Child color="red" fontSize="M" />
そもそも親コンポーネントから子コンポーネントのスタイルを制御するのはアンチパターンな気がしてならないですが...w
少しでもお役に立てれば幸いです🙇♂️
-
コンポーネントライブラリ「Storybook」でこの事象が起きていて、この方法は断念しました。 ↩