Tailwind CSS入門

はてなブックマークへ投稿
Xへポスト
URLをコピー
共有

ウェブでのUIスタイリングには、素のCSSやCSS Modules、CSS-in-JS、UIライブラリを使うなど、さまざまな選択肢があります。その中でも、Tailwind CSSは2010年代後半から徐々に普及してきたCSSフレームワークです。

2026年にはnpmの週間ダウンロード数が1億回を超えるなど、近年さらに利用が拡大しています。Tailwind CSSを使うと、コード上からデザイントークンを意識でき、デザインシステムの基盤としても活用できます。

本記事では、ギャラリーUIのデモを通して、Tailwind CSSの基本的な使い方を紹介します。レイアウト方法やバリアント機能、テーマ定義によってデザインの一貫性を保つ方法や、開発時に注意すべきポイントも解説します。

※この記事ではTailwind CSS v4系を前提にしています。

Tailwind CSSとは

Tailwind CSSは、ユーティリティファーストを特徴とするCSSフレームワークです。独自のクラスを定義する代わりに、小さな役割をもつユーティリティクラスを組み合わせてUIをスタイリングします。

ユーティリティクラスとは、余白や色、文字サイズ、配置の指定など、小さなスタイルです。1つのクラスに1つ以上のCSSプロパティが対応しており、class属性に記載することで対応したスタイルが付与されます。

たとえば、以下のコードはボタンのスタイルの実装例です。

<button
  class="rounded-lg bg-blue-900 px-4 py-2 font-bold text-white"
  type="button"
>
  Button
</button>

同じスタイルをCSSで書くと、次のようになります。

.button {
  border-radius: 0.5rem; /* rounded-lg */
  background-color: oklch(37.9% 0.146 265.522); /* bg-blue-900 */
  padding-inline: 1rem; /* px-4 */
  padding-block: 0.5rem; /* py-2 */
  font-weight: 700; /* font-bold */
  color: #fff; /* text-white */
}

この例では、1つのユーティリティクラスが1つのCSSプロパティに対応していますが、複数まとめて指定するクラスもあります。たとえば、transitionクラスを指定すると以下の3つのCSSプロパティにデフォルト値がまとめて設定されます。

  • transition-property:color、opacity、transform、displayなど多数
  • transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1)
  • transition-duration:150ms

Tailwind CSSの特徴

Tailwind CSSの利点は、スタイル上の制約を設け、コンポーネント実装に集中できることです。

ユーティリティクラスを使うと、余白や色、文字サイズなどTailwind CSSのもつデザイントークンでスタイリングでき、UIに一貫性をもたせやすいです。また、テーマ定義を活用するとプロジェクト独自のスタイルが管理しやすくなります。加えて、UIをスタイリングするたびに.basic-buttonや.button-wrapperといったクラス名を考える手間も減りますし、クラス名が重複して意図しないスタイルになる心配もありません。

スタイルをclass属性に記述するため、CSSファイルを行き来せずにスタイルを確認できる点も利点です。各コンポーネントに適用されているスタイルを追いやすく、共通化すべき箇所にも気づきやすいです。これらはAIを活用した開発でも大きな利点となるでしょう。

一方で、運用にはCSSとTailwind CSS両方の理解が必要になります。開発者に求められる前提知識は多くなってしまう点には注意が必要です。また、テーマ定義などスタイルを縛るルールを決めなければ、どんなスタイルでも使用可能になってしまうため、煩雑なスタイリングを減らす工夫も必要です。

ギャラリーUIの実装デモ

ここからは、Tailwind CSSとReactで実装したギャラリーUIを題材に、スタイリングの重要なポイントを取り上げます。近年のアワード系サイトでよく見られるギャラリーUIを実装しました。画像タイトルにポインターを重ねると、表示画像が追従して切り替わります。デモはデスクトップでご覧ください。

ReactとViteを使用していますが、導入方法は記事『Vite入門』で解説していますので、あわせてご覧ください。

レイアウト

デモUIはギャラリータイトル(GalleryTitle)と画像プレビュー(GalleryPreview)で構成されます。flexを使い、GalleryTitleを縦に並べたエリアと、GalleryPreviewを横並びにします。flexはCSSのdisplay: flexに相当します。

Tailwind CSSの余白に関するクラスはデフォルトで0.25remを基準に計算されます。たとえばpy-10では、上下それぞれに0.25rem × 10 = 2.5remのパディングが指定されます。このようなクラス名を眺めると、対応しているCSSプロパティのイメージがついてくるのではないでしょうか。

/* src/components/Gallery.tsx */
  <div className="... flex ...">
    <ol className="... py-10 ...">
     {galleryItems.map((item, index) => (
        <GalleryTitle ... />
      ))}
    </ol>
    ...
    <GalleryPreview ... />
    ...
  </div>

レスポンシブ対応

Tailwind CSSには、ブレークポイントや疑似クラスなどの条件に応じてスタイルを指定する機能があります。この機能をバリアントといい、ユーティリティクラスの前に条件と:をつけて使います。sm:は画面幅が40rem(640px)以上の場合にスタイルを適用するブレークポイント用のバリアントです。

デスクトップ表示では、sm:w-3/5でタイトル幅を60%に設定し、sm:blockで画像プレビューを表示します。一方、モバイル表示では、w-fullでタイトル幅を100%に広げ、hiddenで画像プレビューを非表示にしています。

/* src/components/Gallery.tsx */
...
  <ol className="w-full ... sm:w-3/5">
    ...
    <GalleryTitle ... />
    ...
  </ol>
  ...
  <div className="hidden sm:block">
    <GalleryPreview ... />
  </div>
...

疑似クラス

バリアントを使うと疑似クラスも利用できます。画像タイトル色はグレーですが、hover:バリアントを使い、ホバー時のみhover:text-foregroundで黒くしています。text-mutedとtext-foregroundは、後述するテーマ定義で用意した、グレーと黒の文字色を指定する独自のクラスです。

/* src/components/GalleryTitle.tsx */
<div className="... text-muted ... hover:text-foreground ...">
  ...
</div>

画像位置の表示

画像の表示位置をタイトルに追従させる処理は、CSSアンカーポジショニングを使っています。デモで使用しているTailwind CSS v4.3.3には、対応するユーティリティクラスが用意されていないため、@utilityディレクティブを使って独自に定義しています。詳しくは記事『CSSアンカーポジショニング入門』をご覧ください。

デモでは、タイトルホバー時にgallery-anchorを付け替えて、アンカー対象のタイトルを切り替えています。画像プレビューのgallery-preview-positionクラスで、画像中心にアンカーがくるようにしつつ、プレビューエリアからはみ出ないようにclamp()で位置を制限しています。

/* src/index.css */
/* 独自に定義したユーティリティ */
@utility gallery-anchor {
  anchor-name: --gallery-active;
}

@utility gallery-preview-position {
  --gallery-preview-width: clamp(12rem, 25vw, 23rem);
  --gallery-preview-height: calc(var(--gallery-preview-width) * 5 / 4);
  position-anchor: --gallery-active;
  /*
    画像の中心をanchor位置に揃える。
    プレビューエリアの上端/下端からはみ出ない位置にclampで制限
  */
  top: clamp(
    calc(var(--spacing) * 10),
    calc(anchor(center) - var(--gallery-preview-height) / 2),
    calc(100% - var(--gallery-preview-height) - var(--spacing) * 10)
  );
}

任意のCSSプロパティをクラス上で指定する機能もありますが、イレギュラーな値を一箇所に切り出せるため、@utilityを使って独自のクラスを定義する方法がオススメです。

Tailwind CSSのバージョンアップでユーティリティクラスが追加されることもあるため、定義したユーティリティを見直し、移行を検討するとよいでしょう。 実際に、Tailwind CSS v4ではstarting:バリアントが追加され、@starting-styleを利用できるようになりました。

テーマ定義とArbitrary Values

Tailwind CSSには、[]を使って任意の値を指定できる Arbitrary Valuesアービトラリー・バリューズ という機能があります。デモではGalleryPreviewでh-[var(--gallery-preview-height)]というクラスを指定し、画像高さにCSS変数を指定しています。柔軟なスタイリングができる便利な機能ですが、多用するとデザインルールから外れた値が増え、UIの一貫性を保ちにくくなります。

スタイルのばらつきを防ぐには、テーマを定義し、プロジェクトで使用する値を共通化することが重要です。Tailwind CSSでは、@themeディレクティブを使ってプロジェクト独自の色や文字サイズなどをテーマ変数として定義できます。テーマ変数の名前は、色なら--color-、文字サイズなら--text-ではじめます。たとえば、--color-foregroundはtext-foregroundやbg-foregroundで使え、--text-gallery-titleはtext-gallery-titleで文字サイズを指定できます。

デモでは、背景色や文字色、罫線色、ギャラリーのタイトルサイズを次のように定義しています。

/* src/index.css */
/* プロジェクト用のテーマ定義 */
@theme {
  --color-canvas: #fff;
  --color-foreground: #0a0a0a;
  --color-muted: #a3a3a3;
  --color-border-subtle: rgb(10 10 10 / 15%);
  --text-gallery-title: clamp(1.25rem, 4vw, 3rem);
}

これにより、テーマに定義した変数からbg-canvasやtext-foreground、border-border-subtle、text-gallery-titleといったクラスを生成しています。

▼ テーマ定義をUIに反映する流れ

テーマ変数をデザイントークンとして活用することで、色や文字サイズなどを一元管理でき、UI全体の統一感を保ちやすくなります。また、AIが生成したスタイルに対し、デザイントークンから逸脱した値に気づきやすくなります。

とはいえ、デザインを忠実に再現する場合など、Arbitrary Valuesを使ってイレギュラーな値を使用せざるをえないケースもあります。基本はテーマで定義した値を使い、例外的なスタイルは必要に応じてクラス化するなど、運用ルールを決めておくとよいでしょう。

Tailwind CSSを使った実装での注意点

Tailwind CSSは便利ですが、注意すべき点もあります。

動的なクラス名は検出されない

Tailwind CSSは、ソースコードを文字列として走査し、検出したクラス名に対応するCSSを生成します。そのため、クラス名にJavaScript変数を含む場合、正しいクラス名として解釈されません。

/* ❌ クラス名の一部にJS変数を使っている */
function Badge({ type, children }) {
  return <span className={`bg-${type}-500 text-white`}>{children}</span>;
}

このようなケースでは、用途ごとのクラス名をあらかじめ用意し、値に応じて切り替える運用がオススメです。

/* ⭕ クラス名をあらかじめ用意して切り替える */
const badgeClasses = {
  info: "bg-cyan-500",
  warning: "bg-rose-500",
};

function Badge({ type, children }) {
  return <span className={`${badgeClasses[type]} text-white`}>{children}</span>;
}

クラス名の誤字は実行時にエラーとして検出されない

Tailwind CSSのクラス名は文字列のため、誤字があってもJavaScriptの実行時エラーにはなりません。たとえば、flexで配置した子要素を縦並びにしたい場合、flex-colとすべきところをflex-columnと誤って記述しても、存在しないクラス名なので対応するCSSは生成されません。

対策として、リンターで存在しないクラス名を検出する方法があります。たとえばESLint用のプラグインであるeslint-plugin-tailwindcssのtailwindcss/no-custom-classnameルールを使うと検出できます。ESLintについては記事『ESLintのルールの選び方と実行タイミング』で詳しく解説しています。

ユーティリティクラスが競合するとスタイルが崩れる

同じCSSプロパティを指定するクラスが重なると、意図しない見た目になることがあります。どちらが適用されるかはclassName内の記述順ではなく、生成されたCSS内での定義順によって決まります。そのため、後から適用したいクラスをclassNameの末尾へ移動するだけでは、意図した結果にならないことがあります。

ユーティリティクラスの競合を整理するには、tailwind-mergeなどのライブラリを利用できます。競合するクラスを判定し、クラス名の一覧から不要なものを取り除きます。

まとめ

本記事では、ギャラリーUIを題材に、Tailwind CSSを使ったレイアウトやバリアント、テーマ定義について紹介しました。注意点はいくつかありますが、テーマを定義して色や文字サイズなどを共通化することで、UIの一貫性を保ちやすくなります。

私見ですがユーティリティクラスを使ってスタイリングすると、このコンポーネントのもつスタイルはこれでよいのか? と実装を見直し、コンポーネント設計について改めて考えるきっかけになります。ぜひTailwind CSSに触れて、ユーティリティファーストなスタイリングを体感してみましょう!

Google検索でICS MEDIAの記事を見つけやすくしよう

優先するソースに追加すると、GoogleのトップニュースやAI検索でICS MEDIAの記事が表示されやすくなります。

Googleで優先するソースとして追加
SNSでシェアしよう
シェアいただくと、サイト運営の励みになります!
はてなブックマークへ投稿
Xへポスト
URLをコピー
共有
岡 大貴

インタラクティブデベロッパー。プログラミング学習支援システムに関する研究で博士(工学)を取得。ウェブ技術を用いた表現やインタラクティブコンテンツについて探求中。

この担当の記事一覧