404 Not Found

404 Not Found


nginx

Vue 3 のクラスおよびスタイルのバインディング:動的なスタイルを記述する 5 つの方法

:class:style は、Vue で最もよく使われる 2 つのバインディングです。これらを使用すると、データに基づいて CSS クラス名やインラインスタイルを動的に切り替えることができます。本質的には、これらは v-bind の 2 つの特別な構文形式であり、非常に頻繁に使用されるため、「構文上の糖衣」として実装されています。

これら5つの記述スタイルを習得すれば、95%のケースに対応できます:オブジェクト構文、配列構文、三項演算子、計算プロパティ、文字列連結

1. 学習内容


2. 注文ステータスラベルのスタイリングに関する課題

(1) 課題:5つの状態、5つのif文

アリスは、管理画面で5つの注文ステータスを異なる色で表示する必要がありました:

HTML
<!-- ❌ The "Flip" Version: 5 v-if with class -->
<span v-if="status === 'pending'" class="badge yellow">Pending</span>
<span v-else-if="status === 'paid'" class="badge green">Paid</span>
<span v-else-if="status === 'shipped'" class="badge blue">Shipped</span>
<span v-else-if="status === 'delivered'" class="badge gray">Delivered</span>
<span v-else class="badge red">Cancelled</span>

プロダクトマネージャーのチャーリー:

「アリス、これじゃ見苦しいよ。来月、ステータスをあと3つ追加することになったらどうする? ただコピー&ペーストするわけにはいかない。すっきりとした動的なアプローチが必要だ。」

(2) Vue :class 解答:たった1行で5つの状態を処理する

VUE
<template>
  <span :class="['badge', statusClass]">{{ statusText }}</span>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({ status: String })

const statusClass = computed(() => ({
  pending: 'yellow',
  paid: 'green',
  shipped: 'blue',
  delivered: 'gray',
  cancelled: 'red'
}[props.status]))

const statusText = computed(() => ({
  pending: 'Pending',
  paid: 'Paid',
  shipped: 'Shipped',
  delivered: 'Delivered',
  cancelled: 'Cancelled'
}[props.status]))
</script>

(3) 収益


3. :class の記述方法 5 選

(1) 文字列の構文

VUE
<template>
  <!-- Static -->
  <div class="active">Static</div>
  
  <!-- Dynamic Strings -->
  <div :class="className">Dynamic</div>
</template>

<script setup>
import { ref } from 'vue'
const className = ref('active text-bold')
</script>

(2) オブジェクト構文(最も一般的)

VUE
<template>
  <!-- Basics: isActive is true, Add active class -->
  <div :class="{ active: isActive }">Single</div>
  
  <!-- Multiple conditions -->
  <div :class="{
    active: isActive,
    'text-danger': hasError,
    disabled: !canEdit
  }">
    Multiple
  </div>
  
  <!-- Computed properties return objects -->
  <div :class="classObject">Computed</div>
</template>

<script setup>
import { ref, computed } from 'vue'

const isActive = ref(true)
const hasError = ref(false)
const canEdit = ref(true)

// Computed Properties:Dynamic Return class Object
const classObject = computed(() => ({
  active: isActive.value && !hasError.value,
  'text-danger': hasError.value,
  'bg-success': isActive.value
}))
</script>

(3) 配列の構文

VUE
<template>
  <!-- Array: Several class concatenation -->
  <div :class="[activeClass, errorClass]">Array</div>
  
  <!-- Trinomial Expression -->
  <div :class="[isActive ? 'active' : '', errorClass]">Ternary</div>
  
  <!-- Array + Object Mixing -->
  <div :class="[activeClass, { 'text-danger': hasError }]">Mixed</div>
  
  <!-- Nested Objects in an Array -->
  <div :class="[{ active: isActive }, errorClass]">Nested</div>
</template>

<script setup>
import { ref } from 'vue'
const activeClass = ref('active')
const errorClass = ref('text-danger')
const isActive = ref(true)
const hasError = ref(false)
</script>

(4) 静的クラスとの共存

VUE
<template>
  <!-- Static + Dynamic Merging(Vue Automatic Merge) -->
  <div class="static-class" :class="{ active: isActive }">
    Both
  </div>
  
  <!-- In the end class: "static-class active" or "static-class" -->
</template>

(5) コンポーネントに関する講義

VUE
<!-- Parent Component -->
<UserCard class="shadow-lg" :class="{ active: isActive }" />

<!-- Child component UserCard.vue -->
<template>
  <!-- Receive -->
  <div :class="$attrs.class">
    <!-- Rendering "shadow-lg active" -->
  </div>
</template>

4. :style の記述方法 5 選

(1) オブジェクト構文

VUE
<template>
  <!-- Basic Objects -->
  <div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
    Object
  </div>
</template>

<script setup>
import { ref } from 'vue'
const activeColor = ref('red')
const fontSize = ref(16)
</script>

(2) CSSプロパティ名の変換

Vue は、JavaScript の命名規則を CSS の命名規則に自動的に変換します:

VUE
<template>
  <div :style="{
    backgroundColor: 'red',        // → background-color
    fontSize: '16px',              // → font-size
    marginTop: '10px',             // → margin-top
    WebkitTransform: 'scale(2)'     // → -webkit-transform
  }">
    CSS naming
  </div>
</template>

(3) 配列の構文(複数のオブジェクトの結合)

VUE
<template>
  <!-- Array:Merge style objects in order(The later one overrides the earlier one)-->
  <div :style="[baseStyles, overrideStyles]">Array</div>
</template>

<script setup>
import { ref } from 'vue'

const baseStyles = ref({
  color: 'blue',
  fontSize: '14px'
})

const overrideStyles = ref({
  color: 'red',  // Coverage baseStyles.color
  fontWeight: 'bold'
})
</script>

(4) 自動プレフィックス付与

Vue 3 は、CSS プロパティに(ブラウザエンジンに基づいて)ブラウザプレフィックスを自動的に追加します:

JS
// Write:
{ transform: 'rotate(45deg)' }

// Vue Auto-add:
{
  -webkit-transform: 'rotate(45deg)',
  transform: 'rotate(45deg)'
}

(5) CSS変数(Vue 3での使用を推奨)

VUE
<template>
  <div :style="{
    '--main-color': mainColor,
    '--spacing': spacing + 'px'
  }">
    CSS Variables
  </div>
</template>

<script setup>
import { ref } from 'vue'
const mainColor = ref('#42b883')
const spacing = ref(20)
</script>

<style>
.dynamic {
  color: var(--main-color);
  padding: var(--spacing);
}
</style>

5. 完全な例:動的な注文状況

(1) ▶ サンプル:. :class の記述方法 5 通り

VUE
<template>
  <!-- 1. String -->
  <div :class="className">String</div>
  
  <!-- 2. Object -->
  <div :class="{ active: isActive, error: hasError }">Object</div>
  
  <!-- 3. Array -->
  <div :class="[activeClass, errorClass]">Array</div>
  
  <!-- 4. Array + Object -->
  <div :class="[activeClass, { disabled: !canEdit }]">Mixed</div>
  
  <!-- 5. Computed Properties -->
  <div :class="dynamicClass">Computed</div>
</template>

<script setup>
import { ref, computed } from 'vue'
const isActive = ref(true)
const hasError = ref(false)
const canEdit = ref(true)
const className = ref('badge')
const activeClass = ref('active')
const errorClass = ref('error')

const dynamicClass = computed(() => ({
  active: isActive.value,
  error: hasError.value,
  'cursor-not-allowed': !canEdit.value
}))
</script>
▶ 試してみよう

(2) ▶ サンプル:. :style の記述方法 5 通り

VUE
<template>
  <!-- 1. Basic Objects -->
  <div :style="{ color: 'red', fontSize: '16px' }">Object</div>
  
  <!-- 2. Multiple properties -->
  <div :style="{ backgroundColor: bg, padding: p + 'px' }">Multi</div>
  
  <!-- 3. Merging Sets -->
  <div :style="[baseStyles, themeStyles]">Array</div>
  
  <!-- 4. CSS Variable -->
  <div :style="{ '--theme-color': theme }">CSS Var</div>
  
  <!-- 5. Computed Properties -->
  <div :style="computedStyle">Computed</div>
</template>

<script setup>
import { ref, computed } from 'vue'
const bg = ref('#42b883')
const p = ref(20)
const theme = ref('#35495e')
const baseStyles = ref({ color: 'white' })
const themeStyles = ref({ backgroundColor: '#42b883' })

const computedStyle = computed(() => ({
  color: 'white',
  backgroundColor: theme.value,
  padding: `${p.value}px`
}))
</script>
▶ 試してみよう

(3) ▶ サンプル:. 注文ステータスバッジ

VUE
<template>
  <span :class="['order-badge', statusClass]">
    {{ statusText }}
  </span>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  status: { type: String, required: true }
})

// 5 Status → 5 class
const statusClass = computed(() => {
  const map = {
    pending: 'bg-yellow',
    paid: 'bg-green',
    shipped: 'bg-blue',
    delivered: 'bg-gray',
    cancelled: 'bg-red'
  }
  return map[props.status] || 'bg-default'
})

const statusText = computed(() => {
  const map = {
    pending: 'Pending',
    paid: 'Paid',
    shipped: 'Shipped',
    delivered: 'Delivered',
    cancelled: 'Cancelled'
  }
  return map[props.status] || 'Unknown'
})
</script>

<style scoped>
.order-badge {
  padding: 4px 12px;
  border-radius: 12px;
  color: white;
  font-size: 12px;
}
.bg-yellow { background: #f59e0b; }
.bg-green { background: #10b981; }
.bg-blue { background: #3b82f6; }
.bg-gray { background: #6b7280; }
.bg-red { background: #ef4444; }
</style>
▶ 試してみよう

(4) ▶ サンプル:. よくある5つの間違い

エラー 症状 解決策
String クラスが反応しない クラスがハードコーディングされており、切り替えられない :class を使用してバインドされている
配列クラスのスペルミス 同じ名前のクラスが複数存在し、互いに上書きし合っている オブジェクト構文の使用
スタイル単位が指定されていません 数値「16」は 16px として解釈され、無視されます 文字列 '16px' が出力されます
誤ったCSSプロパティ名 font-sizefontSize にする キャメルケースまたは引用符を使用
:クラス名の競合 静的 + 動的な名前衝突 Vueが自動的に統合するため問題なし

(5) ▶ サンプル:. 5 性能比較

実装 コンパイル結果 パフォーマンス 適用性
文字列 文字列の直接連結 ⭐⭐⭐⭐⭐ 簡単
オブジェクト 静的解析 ⭐⭐⭐⭐ 中程度
配列 文字列の連結 ⭐⭐⭐⭐ 複数のクラス
配列とオブジェクト 混合処理 ⭐⭐⭐ 複雑
計算プロパティ キャッシュされた値 ⭐⭐⭐⭐⭐ 複雑なロジック

(6) ▶ サンプル:. 「クラス」と「スタイル」の5つの主な違い

側面 クラス スタイル
評価 ⭐⭐⭐⭐⭐ ⭐⭐⭐
CSSの再利用性 容易(クラス名の再利用) 困難(スタイルが散在している)
パフォーマンス 向上(ブラウザの最適化) わずかに低下
優先度 セレクタに依存 インライン(最優先)
テーマの切り替え 簡単(クラスを変更) 簡単(CSS変数を変更)

❓ よくある質問

Q クラスとスタイルのバインディングは共存できますか?
A はい。静的 class="x" と動的 :class="{active: y}" は自動的に統合されます(その結果、class="x active" または "x" のいずれかになります)。
Q なぜ style 属性はオブジェクトとして記述しなければならないのですか?CSS文字列を使えばいいのではないでしょうか?
A はい、可能です。<div style="color: red">はHTMLのネイティブ構文であり、<div :style="'color: red'">も文字列ベースのアプローチです。しかし、オブジェクト:style="{ color: 'red' }"を使用することで、変数を動的にバインドすることができます。オブジェクトの使用をお勧めします。
Q CSS変数はどのように使いますか?
A CSS内で{'--my-var': value}:styleとして、var(--my-var):styleとして使用します。Vue 3では、テーマの切り替えにCSS変数の使用が推奨されています。これは、スタイルを直接バインドするよりも効率的だからです(1つの変数を更新するだけで済み、DOMのリフローも発生しません)。
Q コンポーネントは外部クラスをどのように受け取るのですか?
A シングルルートコンポーネントは、class 属性を自動的に継承します(Vue 3 のデフォルトの動作)。マルチルートコンポーネントは、$attrs.class を使用して特定の要素に明示的にバインドします。
Q 配列構文におけるクラスの順序はどうなりますか?
A 配列内に記述された順序で連結されますが、その順序はCSSの特異性には影響しません(CSSの特異性は、CSSセレクタの特異性によって決まります)。
Q :class は v-if と一緒に使えますか?
A はい。<div v-if="show" :class="{ active: isActive }"> show=false の場合、要素全体がレンダリングされず、isActive は効果を持ちません。
Q テーマを動的に切り替えるにはどうすればよいですか?
A CSS変数の使用をお勧めします。:style="{ '--primary': theme.primary }"はすべての要素color: var(--primary)に適用されます。テーマを切り替えるには、たった1つの変数を変更するだけで済み、100個のクラスを切り替えるよりも効率的です。

📖 まとめ


📝 練習問題

(1) 基礎問題(難易度:⭐)

:class セレクタを使用して、3つのボタン状態を実装します:

データ:const variant = ref('primary')

(2) 上級問題(難易度:⭐⭐)

注文ステータスに応じて、各行に異なる色のバッジが表示される注文リストを実装してください:

(3) チャレンジ問題(難易度:⭐⭐⭐)

完全なテーマ切り替えシステムを実装する:

  1. 3つのテーマ(ライト/ダーク/ハイコントラスト)
  2. CSS変数を使用して、テーマカラー(プライマリ/セカンダリ/背景/テキスト)を紐付ける
  3. :class — テーマクラスの名前を切り替える
  4. localStorage を使ってユーザーの選択内容を記憶する
  5. テーマを切り替えてもページは再読み込みされません(レスポンシブデザインにより自動的に更新されます)
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%