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

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

- 公開日: 2026-06-24
- 著者: 友田 陽大
- タグ: Tailwind CSS, フロントエンド, アクセシビリティ, Next.js, アーキテクチャ設計, パフォーマンス
- URL: https://tomodahinata.com/blog/tailwind-css-v4-css-first-design-tokens-production-guide

## 要点

- Tailwind v4 は設定が JavaScript から CSS へ移り、@import と @theme でデザイントークンを定義する
- デザイントークンを @theme に一元化すると、bg-primary 等のユーティリティが自動生成され DRY になる
- 色を @theme inline で定義するとビルド時に値が焼き込まれ、ランタイムのダークモード切り替えが壊れる
- 生の HSL チャンネル値を :root / .dark に置き、非 inline の @theme でマッピングする二段構えが正解
- prefers-contrast・forced-colors・reduced-motion・:focus-visible を CSS で a11y に組み込む

---

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

---

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

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

```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、`@property`、`color-mix()` を活用。`@starting-style`（出現アニメ）、`not-*` バリアント、`field-sizing`、`inert` などにも対応。

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

---

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

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

```css
@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-lg`、`shadow-sm` が「あなたのデザイン定義」で動きます。色やスペーシングを各コンポーネントにベタ書きする代わりに、トークンを参照する——これが ETC（変更が容易）の核心です。仕様変更はトークン1か所の修正で全画面に波及します。

---

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

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

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

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

```css
@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 をまとめて適用できます。

```css
@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;
}
```

```tsx
// 1クラスで「滑らかに伸縮する見出し」が完成。改行制御は text-balance を併用
<h1 className="text-display-2xl text-balance">見出し</h1>
```

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

---

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

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

```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 実装ガイド](/blog/react-nextjs-web-accessibility-wcag22-guide)を参照してください。

---

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

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

```tsx
<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）。

```css
/* 自前ユーティリティ：本当に何度も使うものだけ */
@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 最適化ガイド](/blog/core-web-vitals-nextjs-inp-lcp-cls-optimization-guide)）。「速いサイトは安いサイト」でもあり、配信コストの削減にも効きます。

---

## 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 設計ガイド](/blog/shadcn-ui-design-system-architecture-production-guide)）。

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

---

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

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

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

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

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