dev TailwindCSS

Tailwind CSS Class Composition 完全ガイド - 複数のユーティリティクラスを組み合わせる方法

Tailwind CSS class composition(クラスの組み合わせ)を実践的に学ぶ完全ガイド。CSS変数を使った内部の仕組みから、filterプロパティの組み合わせ方まで、実際のコード例とブラウザ表示で詳しく解説します。

読者がこの記事から得られる知識

この記事では、Tailwind CSS class composition(クラスの組み合わせ)の基本概念を実践的に学びます。複数のユーティリティクラスを組み合わせて、1つのCSSプロパティに複数の効果を適用する方法を理解できます。

この記事で学べること:

  • Tailwind CSSにおけるclass composition(クラスの組み合わせ)の基本概念
  • 複数のfilter効果(blur、grayscaleなど)を同時に適用する方法
  • CSS変数を使った内部の仕組みと動作原理
  • 通常のCSSとTailwind CSSの違いと、Tailwindが問題を解決する仕組み
  • 実際のコード例とブラウザでの表示確認

実際にコードを書いて、ブラウザで結果を確認しながら学習を進めていきます。「なぜ複数のクラスを書くだけで複数の効果が適用されるのか?」という疑問が解消され、Tailwind CSSの内部の仕組みが理解できるようになります。

今回ハンズオンした内容

今回は、Tailwind CSS公式ドキュメントの「Using class composition」セクション(https://tailwindcss.com/docs/styling-with-utility-classes#using-class-composition)を参照しながら、class composition(クラスの組み合わせ)を実践しました。CSS フレームワークであるTailwind CSSでは、複数のユーティリティクラスを組み合わせることで、1つのCSSプロパティに複数の効果を適用できます。

ファイル構造

tailwindcss/
├── src/
│   ├── index.html
│   ├── input.css
│   └── output.css
├── package.json
├── package-lock.json
└── README.md

ステップ1: フィルター効果を組み合わせたサンプルコードの追加

実行する操作:

src/index.html に、フィルター効果を組み合わせたサンプルコードを追加します。

  <!-- Why not inline styles サンプル: レスポンシブなプロフィールカード -->
  <div class="mt-8 mx-auto max-w-sm">
    <!-- 既存のコード -->
  </div>

  <!-- ↓ ここから追加 -->
  <!-- Using class composition サンプル: フィルター効果の組み合わせ -->
  <div class="mt-8 mx-auto max-w-sm">
    <h2 class="text-2xl font-bold mb-4 text-gray-900 dark:text-white">Filter Effects</h2>

    <!-- 元の画像 -->
    <div class="mb-4">
      <p class="text-sm font-semibold mb-2 text-gray-700 dark:text-gray-300">Original</p>
      <img class="w-full rounded-lg" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=512&q=80" alt="Sample" />
    </div>

    <!-- blur-smのみ -->
    <div class="mb-4">
      <p class="text-sm font-semibold mb-2 text-gray-700 dark:text-gray-300">blur-sm</p>
      <img class="blur-sm w-full rounded-lg" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=512&q=80" alt="Sample" />
    </div>

    <!-- grayscaleのみ -->
    <div class="mb-4">
      <p class="text-sm font-semibold mb-2 text-gray-700 dark:text-gray-300">grayscale</p>
      <img class="grayscale w-full rounded-lg" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=512&q=80" alt="Sample" />
    </div>

    <!-- blur-sm と grayscale を組み合わせ -->
    <div class="mb-4">
      <p class="text-sm font-semibold mb-2 text-gray-700 dark:text-gray-300">blur-sm + grayscale (Combined)</p>
      <img class="blur-sm grayscale w-full rounded-lg" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=512&q=80" alt="Sample" />
    </div>
  </div>
  <!-- ↑ ここまで追加 -->

</body>
</html>

操作の意味:

4つの画像セクションを追加しています:

  • Original: 元の画像(フィルター効果なし)
  • blur-sm: ぼかし効果のみ
  • grayscale: 白黒効果のみ
  • blur-sm + grayscale: 両方の効果を組み合わせ

操作を実行する意図:

class composition(クラスの組み合わせ)の動作を視覚的に確認するためです。特に最後の例では、blur-smgrayscaleという2つのクラスを同時に指定することで、ぼかしと白黒の両方の効果が同時に適用されることを実証します。

実行結果:

ブラウザで表示すると、以下のように4枚の画像が表示されます。

フィルター効果なしの元画像
ぼかしフィルターのみ適用した画像
白黒フィルターのみ適用した画像
blur-smとgrayscaleを組み合わせた画像

実行結果の解説:

期待通り、4枚目の画像では「ぼやけている」かつ「白黒になっている」という2つの効果が同時に適用されています。これは、class="blur-sm grayscale"と書くだけで実現できており、追加のCSSを書く必要がありません。

通常のCSSでは、filterプロパティを2回指定すると後から書いた方が前のものを上書きしてしまいますが、Tailwind CSSではCSS変数を使った巧妙な仕組みによって、複数の効果を組み合わせることができています。

これがclass composition(クラスの組み合わせ)の実例です。

ステップ2: ブラウザの開発者ツールで内部の仕組みを確認

実行する操作:

  1. ブラウザで「blur-sm + grayscale」の画像を右クリック
  2. 「検証」または「要素を調査」を選択
  3. Stylesタブで.blur-sm.grayscaleのCSSを確認

操作の意味:

Tailwind CSSが実際に生成しているCSSを確認します。開発者ツールを使うことで、裏側でどのようなコードが動いているのかを理解できます。

操作を実行する意図:

「なぜクラスを2つ書くだけで、2つの効果が同時に適用されるのか?」という仕組みを理解するためです。実際のCSSを見ることで、Tailwind CSSがCSS変数を使っていることが確認できます。

実行結果:

開発者ツールのStylesパネルに、以下のようなCSSが表示されます:

.grayscale {
  --tw-grayscale: grayscale(100%);
  filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
}

.blur-sm {
  --tw-blur: blur(var(--blur-sm));
  filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) ... (同じfilterプロパティ)
}

実行結果の解説:

重要なポイントが3つあります:

  1. 両方とも同じfilterプロパティを持っている: 通常のCSSなら、後から書いた方が前のものを上書きしてしまいますが、Tailwindでは上書きが起こりません。
  2. 各クラスは自分の担当する変数だけを設定: .grayscale--tw-grayscale変数だけを設定し、.blur-sm--tw-blur変数だけを設定しています。
  3. filterプロパティはすべての変数を参照: どちらのfilterプロパティも、var(--tw-blur, )var(--tw-grayscale, )など、すべての変数を参照しています。変数が未定義なら空になります(フォールバック)。

つまり、.grayscaleだけが適用された場合は--tw-blurは未定義なので空になり、--tw-grayscaleだけが有効になります。.blur-sm.grayscaleの両方が適用された場合は、両方の変数が設定され、両方の効果が有効になります。

これが、Tailwind CSSがCSS変数を使って実現している巧妙な仕組みです。ユーザーからは「クラスを2つ書くだけ」に見えますが、裏側では複雑な仕組みが動いています。

Tailwindは、グラデーション、シャドウの色、transformなどでも同じアプローチを使用しています。

ハンズオンの中で私が疑問に感じた点や失敗した点

よくある疑問

疑問1: 「クラスを2つ書いたら2つの効果が適用される」というのは当たり前では?TailwindCSSが無い場合と比べて何がすごいのですか?

解決手段:

確かに当たり前に見えますが、実は通常のCSSでは簡単にはできません。

通常のCSSで同じことをやろうとすると、こうなります:

.blur-sm {
  filter: blur(4px);
}

.grayscale {
  filter: grayscale(100%);
}
<img class="blur-sm grayscale" src="..." />

結果:grayscaleしか適用されない!

なぜなら、CSSでは後から書いたfilterプロパティが前のものを上書きしてしまうからです。

TailwindCSSは、CSS変数を使ってこの問題を解決しています。各ユーティリティが自分の担当する変数だけを設定し、filterプロパティがすべての変数を参照することで、複数のクラスが協力して1つのfilterを構築します。

これがTailwindCSSの「すごさ」です。

疑問2: CSS変数がどのように動作しているのか、もっと詳しく知りたい

解決手段:

CSS変数(Custom Properties)は、--変数名: 値;の形式で定義し、var(--変数名)で参照できます。Tailwindでは内部的に使用して、複数のクラスを組み合わせ可能にしています。

重要なのは「フォールバック」の仕組みです:

filter: var(--tw-blur, ) var(--tw-grayscale, );

このvar(--tw-blur, )という記述は、「--tw-blur変数が定義されていればその値を使い、定義されていなければ空(何もなし)を使う」という意味です。

この仕組みにより:

  • .blur-smだけが適用された場合:--tw-blurは定義され、--tw-grayscaleは空
  • .grayscaleだけが適用された場合:--tw-grayscaleは定義され、--tw-blurは空
  • 両方が適用された場合:両方の変数が定義され、両方の効果が有効

これが、複数のクラスが「協力して」1つのCSSプロパティを構築できる理由です。

疑問3: 他にどんなプロパティでclass compositionが使われているのか知りたい

解決手段:

Tailwind CSSは、同じアプローチを以下のプロパティでも使用しています:

  1. グラデーション (background-image)
  • bg-gradient-to-r from-purple-500 to-pink-500
  1. シャドウの色 (box-shadow)
  • shadow-lg shadow-blue-500/50
  1. transform (transform)
  • scale-110 rotate-45 translate-x-4

これらすべてが、CSS変数を使って複数の効果を組み合わせられるようになっています。

よくある失敗

失敗1: 任意の値を使って複数のfilterを組み合わせようとする

誤った例:

<img class="[filter:blur(4px)_grayscale(100%)]" src="..." />

エラーメッセージ/結果:
エラーは出ませんが、意図した通りに動作しません。Tailwindのclass compositionの仕組みを使わず、直接CSSを書いているため、他のfilter効果と組み合わせられません。

模範例:

<img class="blur-sm grayscale" src="..." />

ポイント:
Tailwindの用意したユーティリティクラスを使うことで、class compositionの仕組みを活用できます。任意の値は、テーマにない特殊な値が必要な時だけ使いましょう。

失敗2: 通常のCSSのように1つのクラスで複数の効果を定義しようとする

誤った例:

.my-filter {
  filter: blur(4px) grayscale(100%);
}
<img class="my-filter" src="..." />

エラーメッセージ/結果:
この方法自体は動作しますが、Tailwindの他のfilter効果(brightnesscontrastなど)と組み合わせることができません。また、カスタムCSSを増やすことで、Tailwindの「CSSが成長しない」というメリットが失われます。

模範例:

<img class="blur-sm grayscale brightness-110" src="..." />

ポイント:
Tailwindのユーティリティクラスを組み合わせることで、他の効果とも自由に組み合わせられます。カスタムCSSは最小限にとどめ、Tailwindのclass compositionを活用しましょう。

失敗3: CSS変数を自分で設定しようとする

誤った例:

<img style="--tw-blur: blur(10px);" class="grayscale" src="..." />

エラーメッセージ/結果:
blur(10px)は適用されません。なぜなら、Tailwindのfilterプロパティはvar(--blur-sm)のように、さらに別の変数を参照しているためです。

模範例:
特殊なぼかしの強さが必要な場合は、任意の値を使います:

<img class="blur-[10px] grayscale" src="..." />

ポイント:
Tailwindの内部変数を直接操作するのは避けましょう。代わりに、Tailwindが提供する機能(通常のユーティリティクラスまたは任意の値)を使います。

失敗4: filterプロパティを直接上書きしようとする

誤った例:

<img class="blur-sm grayscale" style="filter: brightness(1.2);" src="..." />

エラーメッセージ/結果:
brightness(1.2)だけが適用され、blur-smgrayscaleの効果が消えます。インラインスタイルがTailwindのクラスを上書きしてしまいます。

模範例:

<img class="blur-sm grayscale brightness-120" src="..." />

ポイント:
filterプロパティを直接操作すると、Tailwindのclass compositionの仕組みが壊れます。すべてTailwindのユーティリティクラスで指定することで、複数の効果を自由に組み合わせられます。

失敗5: 同じ効果を重複して指定する

誤った例:

<img class="blur-sm blur-md" src="..." />

エラーメッセージ/結果:
blur-mdだけが適用されます(後から書いた方が優先)。ただし、エラーは出ないため気づきにくいです。

模範例:

<img class="blur-md grayscale" src="..." />

ポイント:
同じ種類の効果(この場合blur)を複数指定しても、最後のものだけが有効になります。1つの効果につき1つのクラスを指定しましょう。

記載内容の翻訳

公式ドキュメント(https://tailwindcss.com/docs/styling-with-utility-classes#using-class-composition)の内容を日本語で読み取れるようにします。

Using class composition

Tailwindでは、単一のCSSプロパティの値を構築するために、複数のクラスを使うことがよくあります。例えば、要素に複数のフィルターを追加する場合:

<div class="blur-sm grayscale">
  <!-- ... -->
</div>

これらの効果はどちらもCSSのfilterプロパティに依存しているため、TailwindはCSS変数を使ってこれらの効果を組み合わせられるようにしています。

生成されるCSSは以下のようになります:

.blur-sm {
  --tw-blur: blur(var(--blur-sm));
  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-grayscale,);
}
.grayscale {
  --tw-grayscale: grayscale(100%);
  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-grayscale,);
}

上記で生成されたCSSは少し簡略化されていますが、ここでのトリックは、各ユーティリティが適用するべき効果だけのCSS変数を設定するということです。その後、filterプロパティがこれらすべての変数を参照し、変数が設定されていない場合は何もフォールバックします。

Tailwindは、グラデーション、シャドウの色、transform などでも同じアプローチを使用しています。

今回のまとめ

お疲れさまでした!今回は、Tailwind CSS class composition(クラスの組み合わせ)について実践的に学習しました。

今回学習したこと:

  • Tailwind CSS class composition(クラスの組み合わせ)により、複数のユーティリティクラスを組み合わせて1つのCSSプロパティに複数の効果を適用できる
  • 通常のCSSでは後から書いたfilterプロパティが前のものを上書きしてしまうが、TailwindはCSS変数を使って複数の効果を協力させることで問題を解決している
  • filterプロパティ以外にも、グラデーション、シャドウの色、transformなどで同じアプローチが使われており、CSS フレームワークとしての一貫性がある

次回は「Using arbitrary values」セクションで、テーマにない値を使う方法を学習します。また別の記事でお会いしましょう!

-dev, TailwindCSS