Class and Style Bindings - 状態に応じた見た目の制御

ロードマップ: Vue.js学習ロードマップ

What(何についてか)

Vue では v-bindclassstyle に対して使う際、単なる文字列だけでなく object や array を使って動的に見た目を制御できる。これにより、状態に応じた class の付け外しや inline style の変更を宣言的に記述できる。

Why(なぜ必要か)

文字列連結で class や style を組み立てると、条件分岐が増えた時に可読性が下がり、保守もしづらくなる。Vue の class/style binding は、状態と見た目の対応関係をデータ構造として表現できるため、テンプレートを簡潔に保ちながら UI の変化を明示的に記述できる。

特に、複数の状態に応じて見た目を切り替える実装では computed() と組み合わせることで整理しやすくなる。

How(どう動くか)

Class binding

:class には object または array を渡せる。

object 構文

<div :class="{ active: isActive, 'text-danger': hasError }"></div>
  • key: class 名
  • value: その class を付与する条件

この構文は class名: 条件 の対応が明快であり、日常的な実装では最も使いやすい。

object を外に切り出す

const classObject = reactive({
  active: true,
  'text-danger': false
})
<div :class="classObject"></div>

条件が増えた時は template 直書きより整理しやすい。

computed と組み合わせる

const isActive = ref(true)
const error = ref(null)
 
const classObject = computed(() => ({
  active: isActive.value && !error.value,
  'text-danger': error.value && error.value.type === 'fatal'
}))
<div :class="classObject"></div>

class 条件が複数の state に依存する場合、class 自体を派生値として computed で表すのが有効である。

array 構文

<div :class="[activeClass, errorClass]"></div>

複数の class 名をリストとして合成できる。さらに object 構文と混在も可能である。

<div :class="[{ [activeClass]: isActive }, errorClass]"></div>

ただし日常的な実装では object 構文の方が読みやすいため、基本は object を主軸にし、array は補助的に扱うとよい。

Component に対する class

component に class を付けると、single root element を持つ子 component ではその root 要素に class がマージされる。

<MyComponent class="baz boo" />

子 component が複数 root を持つ場合は、自動では適用先が決まらないため、$attrs.class を明示的に受け取る必要がある。

Style binding

:style には object または array を渡せる。

object 構文

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

CSS プロパティを JavaScript object として扱う。fontSize のような camelCase が推奨されるが、'font-size' のような kebab-case も使える。

style object を外に切り出す

const styleObject = reactive({
  color: 'red',
  fontSize: '30px'
})
<div :style="styleObject"></div>

template を薄く保ちたい時に有効である。複雑な条件では computed と組み合わせて style object を返す設計も自然である。

array 構文

<div :style="[baseStyles, overridingStyles]"></div>

複数の style object を順にマージできる。ベースのスタイルに対して状態別の上書きを重ねる時に使いやすい。

静的属性との共存

class:classstyle:style は共存でき、最終的にマージされる。

<h1 style="color: red" :style="'font-size: 1em'">hello</h1>

ベンダープレフィックス

ベンダープレフィックスは、ブラウザごとの実験的・過渡期の CSS 実装に付いていた接頭辞である。

例:

  • -webkit-
  • -moz-
  • -ms-

これらは CSS プロパティ名に付く場合と、値に付く場合がある。

-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
display: -webkit-box;
display: -ms-flexbox;
display: flex;

Vue の :style では、複数値を配列で渡して、ブラウザが対応する最後の値を採用させる書き方ができる。

<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

現代の実務ではビルドツールや Autoprefixer が吸収する場面も多く、初学段階で頻繁に意識する必要はない。

実務上の判断軸

  • class は基本 object 構文でよい
  • class 条件が複雑なら computed で object を返す
  • array 構文は補助的機能として知っておけば十分
  • style は object 構文が基本
  • style の array 構文はベース + 上書きの合成で有効
  • component への class 継承は root 要素へ適用されると理解しておけば学習初期は十分

Options API → Composition API 差分(補足)

項目Options API(旧)Composition API(新)
class 条件:class は同じだが state 参照は this.isActiveref / computed を直接参照する
style 条件data() / computed で style object を返すreactive() / computed() で style object を返す
ロジックの配置data, computed に分散しやすい<script setup> で近接配置しやすい

Key Concepts

用語説明
:classclass 属性を動的にバインドする仕組み
object 構文class名: 条件 の対応で class を制御する書き方
array 構文複数 class / style をリストとして合成する書き方
:styleinline style を動的にバインドする仕組み
class merging静的 class と動的 class が最終的に統合されること
style merging複数の style 指定が最終的に統合されること
vendor prefixブラウザ固有の過渡的 CSS 記法に付く接頭辞