メインコンテンツへスキップ
友田 陽大
フロントエンド
Tailwind CSS
フロントエンド
アクセシビリティ
Next.js
アーキテクチャ設計
パフォーマンス

Tailwind CSS v4 実践ガイド【2026年版】— CSS-first 設計・デザイントークン・ダークモード・a11y を本番品質で

Tailwind CSS v4 の CSS-first 設定(@import / @theme / @custom-variant)を本番品質で使いこなす完全ガイド。デザイントークンの単一管理、ランタイムで切り替わるダークモード設計の落とし穴、流体タイポgrafi、container queries、prefers-contrast / forced-colors などアクセシビリティ対応まで実コードで解説します。

公開日
読了時間
10分
著者
友田 陽大
シェア

新しい高速エンジン(Oxide)はフルビルドで最大5倍、増分ビルドで100倍以上高速化されました。しかし真価は速度より「CSS をデザインシステムの単一の真実にできる」点にあります。


1. v3 → v4:何が変わったのか

最大の変化は 設定の場所です。v3 は JS の設定ファイルに色やブレークポイントを書きましたが、v4 は CSS の中で完結します。

/* ❌ v3 の書き方(v4 では誤り) */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* ✅ v4 の正しい書き方:これ1行 */
@import "tailwindcss";
@plugin "@tailwindcss/typography"; /* プラグインも CSS で読み込む */

加えて v4 は次を標準装備しました。

  • 自動コンテンツ検出。 content 配列の手動設定が原則不要になりました。
  • container queries が組み込み(プラグイン不要)。@container@sm: などで親要素サイズに応じたスタイルが書けます。
  • モダン CSS 基盤。 cascade layers、@propertycolor-mix() を活用。@starting-style(出現アニメ)、not-* バリアント、field-sizinginert などにも対応。

設定が JS から消えることで、デザイントークンが「CSS という単一の場所」に集約され、デザインと実装の乖離が減ります。


2. @theme:デザイントークンを一元管理する

@theme で定義した変数は、ただの CSS 変数ではなく「どのユーティリティクラスを生成するか」を決めます。たとえば --color-primary を定義すると bg-primary / text-primary / border-primary が自動で使えるようになります。

@theme {
  /* 角丸トークン */
  --radius-sm: 0.375rem;
  --radius: 0.625rem;
  --radius-lg: 0.875rem;

  /* 影トークン(2層で奥行きを出す) */
  --shadow-sm: 0 1px 2px -1px rgb(16 24 40 / 0.06),
    0 1px 3px 0 rgb(16 24 40 / 0.05);
}

これで rounded-lgshadow-sm が「あなたのデザイン定義」で動きます。色やスペーシングを各コンポーネントにベタ書きする代わりに、トークンを参照する——これが ETC(変更が容易)の核心です。仕様変更はトークン1か所の修正で全画面に波及します。


3. ダークモードの落とし穴:@theme inline が切り替えを壊す

ここが本記事で最も価値のある実務知見です。Tailwind v4 でダークモードを CSS 変数で実装するとき、@theme inline を使うとダークモードが効かなくなります。

理由はこうです。@theme inline は変数の値をビルド時にユーティリティへ焼き込みます。つまり bg-backgroundbackground-color: hsl(0 0% 100%)(ライトの値)として固定され、ランタイムで .dark クラスが付いても変わりません。

正解は「生のチャンネル値を :root / .dark に置き、@theme(非 inline)でトークンへマッピングする」二段構えです。

@custom-variant dark (&:where(.dark, .dark *));

/* ① 生の HSL チャンネル値を単一の真実として持つ */
:root {
  --background: 0 0% 100%;
  --foreground: 222 47% 11%;
  --primary: 222 47% 11%;
  --primary-foreground: 210 20% 98%;
}
.dark {
  --background: 222 47% 5%;
  --foreground: 210 20% 98%;
  --primary: 210 20% 98%;
  --primary-foreground: 222 47% 11%;
}

/* ② 非 inline の @theme でトークンへ。これは
   `--color-*: hsl(var(--channel))` を「本物の CSS 変数」として出力するため、
   var(--channel) がランタイムに解決され、ライト/ダークが正しく切り替わる。 */
@theme {
  --color-background: hsl(var(--background));
  --color-foreground: hsl(var(--foreground));
  --color-primary: hsl(var(--primary));
  --color-primary-foreground: hsl(var(--primary-foreground));
}

ポイントは、色を「HSL のチャンネル三つ組(222 47% 11%)」で保持すること。hsl(var(--token) / <alpha>) の形で任意の透明度を後付けできます(例:bg-primary/15)。@theme inline を選ぶと、この「ランタイム解決」が失われダークモードが死ぬ——この一点だけは必ず覚えてください。


4. 流体タイポグラフィ:1つのユーティリティで4属性を束ねる

見出しのサイズをブレークポイントごとに text-2xl md:text-4xl lg:text-6xl と書くのは冗長です。clamp()@theme修飾子付きトークンを使うと、text-display-2xl ひとつで font-size・line-height・letter-spacing・font-weight をまとめて適用できます。

@theme {
  --text-display-2xl: clamp(2.75rem, 1.6rem + 5.1vw, 5.5rem);
  --text-display-2xl--line-height: 1.08;
  --text-display-2xl--letter-spacing: -0.02em;
  --text-display-2xl--font-weight: 700;
}
// 1クラスで「滑らかに伸縮する見出し」が完成。改行制御は text-balance を併用
<h1 className="text-display-2xl text-balance">見出し</h1>

数値表示には tabular-nums(等幅数字)を当てると桁が揃い、カウントアップ等でガタつきません。これは小さな差ですが、洗練された UI の積み重ねです。


5. アクセシビリティを CSS に組み込む

「a11y は後で」ではなく、トークン設計の段階で組み込みます。Tailwind v4 でも素の CSS メディアクエリがそのまま使えます。

@layer base {
  /* キーボード操作時だけフォーカスリングを見せる */
  :focus-visible {
    outline: 2px solid hsl(var(--ring));
    outline-offset: 2px;
  }

  /* アニメーションは prefers-reduced-motion を尊重 */
  @media (prefers-reduced-motion: reduce) {
    *,
    ::before,
    ::after {
      animation-duration: 0.01ms !important;
      transition-duration: 0.01ms !important;
    }
  }

  /* スクロールバー出現での横ズレ(CLS)を防ぐ */
  html {
    scrollbar-gutter: stable;
  }
}

/* ハイコントラスト設定では、細い罫線と淡色テキストを濃くする */
@media (prefers-contrast: more) {
  :root {
    --border: 222 30% 35%;
    --muted-foreground: 222 25% 28%;
  }
}

/* Windows ハイコントラスト(forced-colors)でもフォーカスを維持 */
@media (forced-colors: active) {
  :focus-visible {
    outline-color: Highlight;
  }
}

色トークンを決める際は コントラスト比 AA(本文 4.5:1、大きな文字 3:1) を満たすこと。淡色テキスト(muted-foreground)はカード上で割り負けやすいので、白背景だけでなく「淡く色の付いた面」でも 4.5:1 を確保する値を選びます。アクセシビリティの全体像はWCAG 2.2 実装ガイドを参照してください。


6. container queries:本当に再利用できるコンポーネント

メディアクエリは「画面幅」で分岐しますが、container queries は「親要素の幅」で分岐します。同じカードをサイドバーにもメイン領域にも置けて、それぞれの幅で最適化されます。これが真の再利用性(ETC)です。

<div className="@container">
  {/* 親が広いときだけ横並びに */}
  <article className="flex flex-col @md:flex-row @md:gap-6">
    <img className="aspect-video @md:w-48" />
    <div>...</div>
  </article>
</div>

「画面が広い」ではなく「この置き場所が広い」で考えると、コンポーネントが配置文脈から独立し、デザインシステムの部品として強くなります。


7. カスタムユーティリティと @apply の使いどころ

繰り返すパターンはカスタムユーティリティに切り出せます。ただし乱用は禁物です(YAGNI)。

/* 自前ユーティリティ:本当に何度も使うものだけ */
@utility container-tight {
  margin-inline: auto;
  max-width: 48rem;
  padding-inline: 1rem;
}

@apply は「既存のクラスをまとめたい誘惑」に駆られますが、多用するとユーティリティファーストの利点(HTML を見れば分かる)を失います。原則は HTML 側でユーティリティを並べること。@apply はデザインシステムのプリミティブ(ボタン等)に限定し、アプリ画面では避けます。


8. パフォーマンスとコスト効率

項目v4 での扱い効果
ビルド速度Oxide エンジン(Rust)フル最大5倍、増分100倍以上
未使用 CSS自動コンテンツ検出+ツリーシェイク本番 CSS が小さく、LCP に有利
配信サイズトークン=CSS 変数で重複が減るキャッシュ効率・転送量を最適化
ランタイムビルド時に静的 CSS 化JS 実行コストゼロ(INP に有利)

CSS が小さく静的であることは、そのまま Core Web Vitals の改善につながります(詳細はCore Web Vitals 最適化ガイド)。「速いサイトは安いサイト」でもあり、配信コストの削減にも効きます。


9. テスト容易性・可観測性

  • コントラストの自動検査。 @axe-core/playwright をCIに組み込み、トークン変更でコントラスト不足が混入しないか検出します。トークンを変えた瞬間に全画面の色が変わるからこそ、自動ガードが効きます。
  • ビジュアルリグレッション。 スナップショット比較で、トークン変更の影響範囲を可視化します。
  • ダーク/ライト両方をテスト。 第3章の設計が壊れていないか、両モードでスクリーンショットを取ります。

10. アンチパターン

  • @theme inline で色を定義してダークモードが死ぬ。 ランタイム切り替えには非 inline +生 CSS 変数を使う(第3章)。
  • 任意値(bg-[#1a2b3c])を各所に散らす。 トークン化して bg-primary に。色の単一の真実が崩れます。
  • :focus { outline: none } でフォーカスを消す。 :focus-visible で見せる。
  • prefers-reduced-motion / forced-colors を無視する。 CSS 数行で対応できる必須事項です。
  • @apply をアプリ画面で多用する。 プリミティブに限定し、画面はユーティリティで組む。
  • メディアクエリだけで部品を作る。 配置文脈に依存しない部品は container queries で。

11. FAQ(よくある質問)

Q. v3 から v4 へ移行すべき? A. 新規プロジェクトは v4 一択です。既存は公式の upgrade ツールがありますが、@tailwind ディレクティブの置換、設定の CSS 化、プラグイン読み込みの変更が必要なため、影響範囲を確認してから移行します。

Q. tailwind.config.js はもう使えない? A. CSS-first が標準ですが、互換のための JS 設定読み込みも可能です。新規は CSS の @theme を推奨します(単一の場所に集約できるため)。

Q. ダークモードが切り替わらない。 A. 最有力の原因は @theme inline での色定義です。生の CSS 変数を :root/.dark に置き、非 inline の @theme でマッピングしてください(第3章)。

Q. shadcn/ui と併用できる? A. 相性は抜群です。shadcn は CSS 変数ベースのテーマを前提としており、本記事のトークン設計とそのまま噛み合います(shadcn/ui 設計ガイド)。

Q. デザイントークンはどこまで細かく分ける? A. 「意味」で分けます(primary / muted / destructive)。色そのもの(blue-500)ではなく役割で名付けると、リブランドや配色変更が1か所で済みます。


まとめ:CSS をデザインシステムの単一の真実にする

Tailwind v4 の本質は速度ではなく、設計の集約です。色・タイポ・角丸・影・ブレークポイントを @theme に集め、そこからユーティリティが生成され、a11y もコントラストもダークモードも同じ場所で管理する——これが破綻しないデザインシステムの土台になります。

  1. @import + @themeCSS-first 設定に統一。
  2. 色は生チャンネル+非 inline @theme でランタイム・ダークモード対応。
  3. 流体タイポ・container queries で配置文脈に強い部品を作る。
  4. prefers-contrast / forced-colors / reduced-motion / :focus-visiblea11y を CSS に内蔵
  5. 静的 CSS の軽さで パフォーマンスとコストを最適化

デザインの一貫性は、プロダクトの信頼感に直結します。トークンが整っているプロダクトは、見た目だけでなく保守性・拡張性も高い。

デザインシステムの構築や、Tailwind v4 への移行・テーマ設計が必要な場合は、お気軽にご相談ください。 下記の事例では、多言語・多文化のユーザーが使う UI を、一貫したデザインと操作性で設計・実装した過程を紹介しています。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

外国人旅行客向け飲食店マッチングサイト

ケーススタディを見る