はじめに
こんにちは!
WEBCAMP ENGINEER COMMUNITY Advent Calendar 2022
18日目担当のTOKIOです!
本業のフロントエンド開発にて、Vue.jsを使用しているのですが、
子コンポーネントのCSSは変えずに、親から子コンポーネントの色、デザインを変えたい、という場面に直面しました。
今回の記事は、そんな時に親コンポーネントから子コンポーネントのCSSを変更する方法をご紹介します!
※Vue:3.2.41,Vuetify:3.0.2を使用しています。
使用画面
↑上記の子コンポーネント(v-card)を親コンポーネント側からCSSで色を変更します!
子コンポーネントのコード
※SCSS記法を使用しています。
<template>
<v-card class="card">
<v-card-title class="title"> タイトル </v-card-title>
<v-card-text> テキスト</v-card-text>
<v-btn>ボタン</v-btn>
</v-card>
</template>
<style lang="scss" scoped>
.card {
.title {
background-color: blue;
}
.v-card-text {
background-color: green;
}
.v-btn {
background-color: yellow;
}
}
</style>
親から子にCSSを適用する
親から子にCSSを適用する方法は、(自分が知る限りでは)2パターンあります。
方法①『ディープセレクタ(v-deep)を使う』
この方法では、ディープセレクタ(v-deep)を使って親から子のセレクタを指定して、CSSを適用しています。
実際のコード(親コンポーネント)
<template>
<Child></Child><!--子コンポーネント-->
</template>
<style lang="scss" scoped>
::v-deep(.card) {/**v-deepで子コンポーネントのクラスor要素を指定)**/
.title {
background-color: green;
}
.v-card-text {
background-color: blue;
}
.v-btn {
background-color: red;
}
}
</style>
::v-deepの後ろに()で要素をセレクタするだけです。
方法②『グローバルCSSを使う』
※この方法はあまりオススメしません!理由は後述
この方法では、CSSのscopedというVue側でコンポーネント毎にCSSを付与させる属性を外し、
CSSをローカルスタイル(使用コンポーネントのみ)ではなく、グローバルスタイル(他画面にも影響させる)に変更することを意味します。
実際のコード(親コンポーネント)
<template>
<div class="child">
<Child></Child><!--子コンポーネント-->
</div>
</template>
<style lang="scss">/**scopedをつけない**/
.child {
.card {
.title {
background-color: green;
}
.v-card-text {
background-color: blue;
}
.v-btn {
background-color: red;
}
}
}
</style>
方法②をオススメしない理由
結論、他の画面のCSSにも影響を及ぼしたり、CSS同士が競合してしまう可能性があるからです。
グローバルスタイルでCSSを適用してしまうと、他の画面からグローバルスタイルで同じ要素にCSSを適用しようとすると、競合が発生し、優先度が低いCSSが打ち消されてしまいます。
(!importantで乗り切れるけど、アンチパターン)
また、実際のコードを見ていただけるとわかるのですが、子コンポーネントを子コンポーネントをdivタグなどで囲み、クラスを指定する必要があります。
親のクラスから子のクラスに潜る必要があるので、不要な要素が一つ増えてしまうのです。
上記の理由から、グローバルスタイルが汚染されるのと、コンポーネント同士のCSSの連携がぐちゃぐちゃになるので、方法①を使うことをオススメします!
方法①or②を使用した後の画面
おわりに
上記のように親から子のCSSを書き換えることができます。
要素やサイズは大体同じだけど、「この画面では違うデザインにしたい!」
という時にとても重宝するCSSの適用の仕方だと思います。
ディープセレクタは他にも書き方があるみたいですが、sassなどのモジュールのバージョンによって適用されなかったり、エラーが発生する場合があるそうなので、基本的にv-deepを使用すれば間違いないと思います。
親から子にscopedを付けながらCSSを適用するのは、ドキュメントを読んでも当時は分からなかったので、なかなか苦しみました(笑)
この記事を読んで、Vue使いの方がもっと幅広いデザインを作成できるようになれば嬉しい限りです🙇
ご愛読、ありがとうございました!