VueのSFC CSSの注意点

Vueにはスコープ付きCSSというコンポーネント内でのみ適用されるstyleタグを定義できる。

Vueコンポーネントは大体それを使ってレイアウトすれば他のコンポーネントのスタイルはあまり気を使わなくて良いはず。

ある時 <style scoped>としているのに、子コンポーネントに親のスタイルが反映されるトラブルが発生した。

deepなどは使っていないのに妙だな~と思って原因を調査したところVueの公式ドキュメントに以下のように書いてあった。

しかし、子コンポーネントのルートノードは親のスコープ付き CSS と子のスコープ付き CSS の両方の影響を受けることになります。

つまり子コンポーネントのルートノードで参照してるクラス名が親のクラス名と一致していると、親のスコープ付きCSSも適用されてしまうのである。

これは意図された設計で、以下のように続いている。

親がレイアウト目的で子ルート要素のスタイルを設定できるようにするための設計です。

Vueのスコープ付きCSSはCSS Modulesのようにクラス名を書き換える仕組みではなく、コンパイル時に独自属性を付与してセレクターを絞り込む仕組みになっている。

たとえば以下のようなコードがあったとする。

Parent.vue
<template>
<article class="card"></article>
<Child />
</template>
<style scoped>
.card {
color: red;
}
</style>
Child.vue
<template>
<article class="card"> // ルートノード
</article>
<template>
<style scoped>
.card {
padding: 10px;
}
</style>

このようにルートノードで親と同じクラス名を参照していると、ルートノードに両方のスコープ属性が付与されて子コンポーネントも赤色になる。

// Childのレンダリング後のイメージ
<article class="card" data-v-parent data-v-child></article>

ルートノードに関しては完全な隔離ではないことを理解し、スコープ付きCSS内でも管理しやすい命名を心がけることが重要である。