本文へジャンプ

SFC CSS 機能

スコープ付き CSS

<style> タグに scoped 属性が指定されている場合、その CSS は現在のコンポーネントの要素のみに適用されます。これは、Shadow DOM に見られるスタイルのカプセル化に似ています。これはいくつかの注意点がありますが、ポリフィルは必要ありません。これは、PostCSS を使って変換することで実現されます。次のコードは:

vue
<style scoped>
.example {
  color: red;
}
</style>

<template>
  <div class="example">hi</div>
</template>

以下のように変換されます:

vue
<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style>

<template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>

子コンポーネントのルート要素

scoped を使用すると、親コンポーネントのスタイルが子コンポーネントに漏れることはありません。しかし、子コンポーネントのルートノードは親のスコープ付き CSS と子のスコープ付き CSS の両方の影響を受けることになります。これは、親コンポーネントがレイアウトのために子コンポーネントのルート要素のスタイルを設定できるようにするための設計です。

deep セレクター

scoped スタイルのセレクターを "deep" にしたい場合、つまり子コンポーネントに影響を与えたい場合は、:deep() 擬似クラスを使用できます:

vue
<style scoped>
.a :deep(.b) {
  /* ... */
}
</style>

上記は次のようにコンパイルされます:

css
.a[data-v-f3f3eg9] .b {
  /* ... */
}

TIP

v-html で作成された DOM コンテンツは、スコープ付きスタイルの影響を受けませんが、deep セレクターを使用してスタイルを設定可能です。

slotted セレクター

<slot/> によってレンダリングされるコンテンツは、デフォルトでは親コンポーネントによって所有されていると見なされるため、スコープ付きスタイルの影響を受けません。明示的にスロットのコンテンツをターゲットにするには、:slotted 疑似クラスを使用します:

vue
<style scoped>
:slotted(div) {
  color: red;
}
</style>

global セレクター

もし 1 つのルールだけをグローバルに適用したい場合は、別の <style> を作成するかわりに、:global 疑似クラスを使用できます(以下を参照):

vue
<style scoped>
:global(.red) {
  color: red;
}
</style>

ローカルスタイルとグローバルスタイルの混在

スコープ付きスタイルとスコープなしスタイルの両方を同じコンポーネントに含めることもできます:

vue
<style>
/* グローバルスタイル */
</style>

<style scoped>
/* ローカルスタイル */
</style>

スコープ付きスタイルのヒント

  • スコープ付きスタイルでクラスが不要になるわけではありません。ブラウザーの様々な CSS セレクターのレンダリング方法により、p { color: red } をスコープ付きにした場合(つまり属性セレクターと組み合わせた場合)、何倍も遅くなります。その代わり、.example { color: red } のようにクラスや ID を使用すれば、このパフォーマンス低下をほぼ排除できます。

  • 再帰的コンポーネントでの子孫セレクターに注意! .a .b というセレクターがある CSS ルールにおいて、.a にマッチする要素が再帰的な子コンポーネントを含む場合、その子コンポーネントのすべての .b がルールにマッチされます。

CSS モジュール

<style module> タグは CSS モジュールとしてコンパイルされ、結果として得られる CSS クラスを $style というキーの下にオブジェクトとしてコンポーネントに公開します:

vue
<template>
  <p :class="$style.red">This should be red</p>
</template>

<style module>
.red {
  color: red;
}
</style>

生成されたクラスは衝突を避けるためにハッシュ化され、CSS を現在のコンポーネントのみにスコープするのと同じ効果を得ることができます。

グローバルの例外コンポジションなどの詳細は、CSS モジュールの仕様を参照してください。

カスタム注入名

module 属性に値を与えることで、注入されるクラスオブジェクトのプロパティキーをカスタマイズできます:

vue
<template>
  <p :class="classes.red">red</p>
</template>

<style module="classes">
.red {
  color: red;
}
</style>

Composition API での使用

注入されたクラスは、useCssModule API を介して setup()<script setup> の中でアクセスできます。カスタム注入名を持つ <style module> ブロックの場合、useCssModule は最初の引数としてマッチする module 属性の値を受け取ります:

js
import { useCssModule } from 'vue'

// setup() スコープの内側...
// デフォルトでは <style module> のクラスを返します
useCssModule()

// 名前付きの例、<style module="classes"> のクラスを返します
useCssModule('classes')
vue
<script setup lang="ts">
import { useCssModule } from 'vue'

const classes = useCssModule()
</script>

<template>
  <p :class="classes.red">red</p>
</template>

<style module>
.red {
  color: red;
}
</style>

CSS の v-bind()

SFC の <style> タグでは v-bind という CSS 関数を使用して、CSS の値をコンポーネントの動的な状態にリンクすることをサポートします:

vue
<template>
  <div class="text">hello</div>
</template>

<script>
export default {
  data() {
    return {
      color: 'red'
    }
  }
}
</script>

<style>
.text {
  color: v-bind(color);
}
</style>

この構文は <script setup> で動作し、JavaScript の式(引用符で囲む必要あり)をサポートします:

vue
<script setup>
import { ref } from 'vue'
const theme = ref({
    color: 'red',
})
</script>

<template>
  <p>hello</p>
</template>

<style scoped>
p {
  color: v-bind('theme.color');
}
</style>

実際の値は、ハッシュ化された CSS カスタムプロパティにコンパイルされるため、CSS は静的なままです。カスタムプロパティは、インラインスタイルによってコンポーネントのルート要素に適用され、ソース値が変更されるとリアクティブに更新されます。

SFC CSS 機能が読み込まれました