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

「モバイルファースト」を正しく理解する
Tailwindのレスポンシブ設計で最初につまずくポイントは、sm:の意味です。「smってsmall=スマホ用じゃないの?」と思いがちですが、まったく逆。Tailwindのブレイクポイントは「最小幅(min-width)」ベースです。sm:は「640px以上」で発動する——つまり、スマホではなく「スマホより大きい画面」で適用されるクラスです。
この設計思想は「まずモバイルのスタイルを素のクラスで書き、大きい画面向けにブレイクポイント付きクラスを上書きしていく」というもの。デフォルトがモバイル、プレフィックス付きが大画面用。この原則さえ頭に入れば、Tailwindのレスポンシブは直感的に書けます。
/* ブレイクポイント 最小幅 生成される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) { ... }
<!-- これは640px以上でのみ中央寄せ。モバイルでは左寄せのまま -->
<div class="sm:text-center">テキスト</div>
<!-- モバイルで中央寄せ、640px以上で左寄せに切り替え -->
<div class="text-center sm:text-left">テキスト</div>
class="text-center sm:text-left"
このテキストはブラウザ幅で配置が変わります
↑ ブラウザ幅を640px未満にすると中央揃え、640px以上で左揃えになります
基本パターン:カード列のレスポンシブ切り替え
実務で最も多い「カードを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つ分のレスポンシブ対応が完了します。
↑ ~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>
↑ ~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-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>
↑ ブラウザ幅を変えると表示が切り替わります
要素の表示・非表示をレスポンシブに切り替える
実務でよく出るパターンとして、「スマホではハンバーガーメニュー、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>
レスポンシブ見出し
↑ 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)で特定の祖先コンテナを指定することも可能です。
↑ 親要素のリサイズに反応して縦→横レイアウトが切り替わる
カスタムブレイクポイントと任意の値
デフォルトの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>
↑ モバイル: 縦積み / 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構文が使える