Tailwind CSSでレスポンシブデザイン ―
モバイルファーストの書き方と実践パターン

「sm: ってスマホ用でしょ?」——いいえ、違います。Tailwindのブレイクポイントは「その幅以上」で発動するモバイルファースト設計。この仕組みを正しく理解すれば、レスポンシブ対応がクラス名を足すだけで完結します。

「モバイルファースト」を正しく理解する

Tailwindのレスポンシブ設計で最初につまずくポイントは、sm:の意味です。「smってsmall=スマホ用じゃないの?」と思いがちですが、まったく逆。Tailwindのブレイクポイントは「最小幅(min-width)」ベースです。sm:は「640px以上」で発動する——つまり、スマホではなく「スマホより大きい画面」で適用されるクラスです。

この設計思想は「まずモバイルのスタイルを素のクラスで書き、大きい画面向けにブレイクポイント付きクラスを上書きしていく」というもの。デフォルトがモバイル、プレフィックス付きが大画面用。この原則さえ頭に入れば、Tailwindのレスポンシブは直感的に書けます。

v4 デフォルトのブレイクポイント一覧
/* ブレイクポイント    最小幅         生成されるCSS */
sm:              40rem (640px)   @media (width >= 40rem) { ... }
md:              48rem (768px)   @media (width >= 48rem) { ... }
lg:              64rem (1024px)  @media (width >= 64rem) { ... }
xl:              80rem (1280px)  @media (width >= 80rem) { ... }
2xl:             96rem (1536px)  @media (width >= 96rem) { ... }
❌ よくある間違い:sm: でモバイルを指定しようとする
<!-- これは640px以上でのみ中央寄せ。モバイルでは左寄せのまま -->
<div class="sm:text-center">テキスト</div>
✅ 正しい書き方:プレフィックスなし=モバイル
<!-- モバイルで中央寄せ、640px以上で左寄せに切り替え -->
<div class="text-center sm:text-left">テキスト</div>
▶ Live Demo — モバイルファーストの実感

class="text-center sm:text-left"

このテキストはブラウザ幅で配置が変わります

↑ ブラウザ幅を640px未満にすると中央揃え、640px以上で左揃えになります

💡 現場の経験則
実務でのコツ:まずモバイル画面をデザインツールで見ながらクラスを書き、次にmdやlgのプレフィックスを足して大画面対応する——という順番で作業すると迷いません。「小さい画面から大きい画面に広げていく」のがTailwindの自然な流れです。

基本パターン:カード列のレスポンシブ切り替え

実務で最も多い「カードを1列→2列→3列に変化させる」パターンを、Tailwindでどう書くかを見てみましょう。

レスポンシブなカードグリッド
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
  <div class="bg-white rounded-xl p-6 shadow-sm">カード1</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">カード2</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">カード3</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">カード4</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">カード5</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">カード6</div>
</div>

読み方はこうです:デフォルト(モバイル)はgrid-cols-1で1列。640px以上(sm:)で2列に。1024px以上(lg:)で3列に。たった1行のクラスで、メディアクエリ3つ分のレスポンシブ対応が完了します。

▶ Live Demo — レスポンシブグリッド(ブラウザ幅を変えてみてください)
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6

↑ ~639px: 1列 / 640px~: 2列 / 1024px~: 3列

ナビゲーションの切り替え

もう一つ頻出なのが、ナビゲーションのレイアウト切り替えです。モバイルでは縦積み、タブレット以上で横並びにするパターンを見てみましょう。

レスポンシブなナビゲーション
<nav class="flex flex-col md:flex-row md:items-center md:justify-between gap-4 p-4">
  <a class="text-xl font-bold">Logo</a>
  <ul class="flex flex-col md:flex-row gap-2 md:gap-6 text-sm">
    <li><a class="hover:text-blue-600">Home</a></li>
    <li><a class="hover:text-blue-600">About</a></li>
    <li><a class="hover:text-blue-600">Contact</a></li>
  </ul>
</nav>
▶ Live Demo — ナビゲーション切り替え
Logo
Home About Contact

↑ ~767px: 縦積み / 768px~: 横並びでspace-between

ここでのポイントはflex flex-col md:flex-rowです。デフォルト(モバイル)でflex-direction: columnにしておき、md:rowに切り替える。gapもgap-2 md:gap-6と幅に応じて広げています。この「デフォルトが狭い画面、プレフィックスで広い画面」のリズムを体に染み込ませましょう。

max-* バリアントとブレイクポイント範囲

「特定の画面幅だけにスタイルを適用したい」——そんなときに使うのがmax-*バリアントです。v4ではデフォルトのブレイクポイントそれぞれに対応するmax-*が自動生成されています。

max-* バリアント一覧
max-sm:   /* @media (width < 40rem)  → 640px未満 */
max-md:   /* @media (width < 48rem)  → 768px未満 */
max-lg:   /* @media (width < 64rem)  → 1024px未満 */
max-xl:   /* @media (width < 80rem)  → 1280px未満 */
max-2xl:  /* @media (width < 96rem)  → 1536px未満 */

そしてここが面白いところ。md:max-xl:をスタック(重ねがけ)すると、「768px以上かつ1280px未満」という範囲指定ができます。

ブレイクポイント範囲の指定
<!-- md(768px)以上 かつ xl(1280px)未満 でのみ表示 -->
<div class="hidden md:max-xl:block">
  タブレット〜小さめPCのみ表示されるコンテンツ
</div>

<!-- モバイル(640px未満)のみ表示 -->
<div class="max-sm:block hidden">
  スマホだけに見せたいUI
</div>
▶ Live Demo — ブレイクポイント範囲を体感
max-sm: → 640px未満で表示(今あなたの画面幅に応じて表示)
md:max-xl: → 768px〜1279pxで表示
xl: → 1280px以上で表示

↑ ブラウザ幅を変えると表示が切り替わります

⚠️ 注意
max-*バリアントは便利ですが、多用するとモバイルファーストの流れが崩れて「どの幅で何が適用されるか」が追いにくくなります。基本はプレフィックスなし→sm→md→lgと積み上げる設計で、max-*は本当に「その範囲限定のスタイル」が必要なときだけ使うのがおすすめです。

要素の表示・非表示をレスポンシブに切り替える

実務でよく出るパターンとして、「スマホではハンバーガーメニュー、PCでは通常ナビ」のように、画面幅に応じて要素そのものを出し入れする場面があります。

表示/非表示の切り替え
<!-- モバイルメニューボタン:md以上で消す -->
<button class="md:hidden"></button>

<!-- デスクトップナビ:モバイルでは隠す -->
<nav class="hidden md:flex gap-6">
  <a>Home</a>
  <a>About</a>
  <a>Contact</a>
</nav>

hidden md:flexの読み方:デフォルト(モバイル)でdisplay: none、768px以上でdisplay: flex。逆にmd:hiddenは「768px以上でnone」。このパターンはヘッダーだけでなく、サイドバーの出し入れ、テーブルの列表示制御など、あらゆる場面で使えます。

レスポンシブなフォントサイズとスペーシング

レスポンシブ対応はレイアウトだけではありません。見出しのサイズや余白も画面幅で調整するのが実務の基本です。

画面幅に応じてサイズを段階的に大きくする
<h1 class="text-2xl md:text-4xl lg:text-5xl font-bold">
  見出しテキスト
</h1>

<section class="py-8 md:py-16 lg:py-24 px-4 md:px-8">
  <!-- 画面が大きいほど余白も広く -->
</section>
▶ Live Demo — レスポンシブなタイポグラフィ

レスポンシブ見出し

↑ text-2xl → md:text-4xl → lg:text-5xl の切り替えイメージ

コンテナクエリ — ビューポートではなく「親要素の幅」で判定

Tailwind CSS v4では、コンテナクエリがコアに統合されました。ビューポート幅ではなく、親要素の幅に応じてスタイルを変えられる機能です。再利用可能なコンポーネントを作るとき、これが本領を発揮します。

たとえば同じカードコンポーネントが「サイドバー(狭い)」と「メインエリア(広い)」の両方に配置される場合を考えてください。ビューポートベースのブレイクポイントでは対応できないですよね。そこでコンテナクエリの出番です。

コンテナクエリの基本
<!-- 親に @container を指定 -->
<div class="@container">

  <!-- 子要素で @md: や @lg: を使う -->
  <div class="flex flex-col @md:flex-row gap-4">
    <img class="w-full @md:w-48 rounded-lg" src="..." />
    <div>
      <h3 class="text-lg font-bold">タイトル</h3>
      <p class="text-sm text-gray-600">説明文</p>
    </div>
  </div>

</div>
コンテナクエリのサイズ一覧(抜粋)
@3xs:  16rem (256px)
@2xs:  18rem (288px)
@xs:   20rem (320px)
@sm:   24rem (384px)
@md:   28rem (448px)
@lg:   32rem (512px)
@xl:   36rem (576px)
@2xl:  42rem (672px)
@3xl:  48rem (768px)

ブレイクポイントと同じくモバイルファースト設計で、@md:は「コンテナ幅448px以上で適用」です。@max-md:で上限指定もできますし、名前付きコンテナ(@container/sidebar)で特定の祖先コンテナを指定することも可能です。

▶ Live Demo — コンテナクエリ(右下をドラッグしてリサイズ)
ユーザー名 コンテナ幅400px以上で横並びに切り替わります。右下のハンドルをドラッグしてリサイズしてみてください。

↑ 親要素のリサイズに反応して縦→横レイアウトが切り替わる

📌 ポイント
コンテナクエリとビューポートブレイクポイントは併用できます。ページ全体のレイアウト(2カラム↔1カラム)はビューポートベースのmd:で、個々のコンポーネントの内部レイアウトはコンテナクエリ@md:で——と使い分けるのが実務的なベストプラクティスです。

カスタムブレイクポイントと任意の値

デフォルトの5段階(sm〜2xl)で足りない場合は、@themeディレクティブで自由に追加・変更できます。

カスタムブレイクポイントの追加
@import "tailwindcss";

@theme {
  --breakpoint-xs: 30rem;    /* 480px — 小さめスマホ */
  --breakpoint-3xl: 120rem;  /* 1920px — ワイドモニター */
}
追加したブレイクポイントを使う
<div class="grid grid-cols-2 xs:grid-cols-3 3xl:grid-cols-6">
  <!-- xs: と 3xl: が新しく使える -->
</div>

「一度だけ使いたい特殊な幅」の場合は、テーマに追加せず任意値(arbitrary value)構文が使えます。

任意のブレイクポイント(一度きりの値)
<!-- 320px以上で中央寄せ、600px未満でsky色の背景 -->
<div class="min-[320px]:text-center max-[600px]:bg-sky-300">
  コンテンツ
</div>
⚠️ 注意
ブレイクポイントの単位は必ずremで統一してください。pxとremを混在させると、生成されるCSSの並び順がおかしくなり、ブレイクポイント同士が意図しない上書きをする可能性があります。デフォルトがremなので、カスタムもremで合わせるのが安全です。
▶ Live Demo — レスポンシブユーティリティの組み合わせ実例
メインコンテンツ
サイドバー

↑ モバイル: 縦積み / 768px〜: 2:1の横並び(flex flex-col md:flex-row のイメージ)

まとめ

  • Tailwindのブレイクポイントはmin-width(モバイルファースト)。sm: は「640px以上」であり、スマホ用ではない
  • プレフィックスなしがモバイルスタイル。sm: → md: → lg: と順に大画面向けクラスを追加していくのが基本の流れ
  • max-sm: / max-md: などのmax-*バリアントで「〜未満」の指定が可能。md:max-xl: のスタックで範囲指定もできる
  • hidden md:flex(モバイルで非表示→md以上で表示)は超頻出パターン。ナビ、サイドバー、テーブル列の制御に使う
  • v4ではコンテナクエリがコア統合。@container を親に付け、@md: で親要素の幅に応じたスタイリングができる
  • カスタムブレイクポイントは @theme で --breakpoint-* を定義。単位はrem統一が必須
  • 一度きりの値には min-[320px]: / max-[600px]: のarbitrary構文が使える