Tailwind CSSのFlex & Gridユーティリティで作る ― 実務で使えるレイアウトパターン集

Flexboxで横並べ、Gridで格子状に……基本はわかっているけど「結局どっちを使えばいいの?」が曖昧なままになっていませんか。この記事では、Tailwind CSS v4のユーティリティを使って、現場で頻出するレイアウトパターンをそのまま使えるコード付きで紹介します。

FlexboxとGrid、どう使い分ける?

「カードを3列に並べたい」——こんなとき、あなたは flexgrid のどちらを選びますか? どちらでも実現はできるけど、「自然で壊れにくい方」はテーマによって違います。ざっくりした判断基準を最初に整理しておきましょう。

Flexboxは「1次元(横 or 縦の1列)のコンテンツ配置」が得意です。ナビゲーション、ボタンの横並び、テキストとアイコンの位置合わせなど、「1行のなかで柔軟に配置する」場面で真価を発揮します。一方Gridは「2次元(行 × 列)のレイアウト設計」が本領。カード一覧、ダッシュボード、雑誌風のレイアウトなど、「面」で設計するときに圧倒的に強い。

現場でのポイントは「子要素の数や幅が予測しにくい → Flex」「行と列を同時にコントロールしたい → Grid」という判断です。もちろん組み合わせて使うことも多く、Grid全体レイアウトの中にFlexのナビバーが入る……というのが実際のコード構造です。

Flex vs Grid ― Tailwindでの基本宣言の違い
<!-- Flexbox: 1次元レイアウト -->
<div class="flex items-center gap-4">
  <img class="w-10 h-10 rounded-full" />
  <span>ユーザー名</span>
</div>

<!-- Grid: 2次元レイアウト -->
<div class="grid grid-cols-3 gap-6">
  <div>カード1</div>
  <div>カード2</div>
  <div>カード3</div>
</div>
▶ Live Demo — Flex(上)とGrid(下)の違い

FLEXBOX — 子要素のサイズに合わせて伸縮

短い
少し長いテキスト
中くらい

GRID — 均等なカラム幅で整列

短い
少し長いテキスト
中くらい
💡 現場の経験則
迷ったら「子要素が全部同じ幅で並ぶか?」を考えてみてください。Yesなら Grid、Noなら Flex。たとえばタグの羅列(幅バラバラ)は Flex + flex-wrap、商品カード一覧(同じ幅で揃えたい)は Grid が自然です。

Flexboxパターン① ― ナビバー & ヘッダー

Flexbox最大の出番がヘッダー・ナビゲーションです。「左にロゴ、右にメニュー」「アイテムを等間隔に並べる」——こういった1行の配置問題は、Tailwindなら3〜4クラスで解決します。

ヘッダー:ロゴ左・ナビ右のスペースビトウィーン
<header class="flex items-center justify-between px-6 py-4">
  <a class="text-xl font-bold">Logo</a>
  <nav class="flex gap-6 text-sm">
    <a class="hover:text-cyan-600">Home</a>
    <a class="hover:text-cyan-600">About</a>
    <a class="hover:text-cyan-600">Contact</a>
  </nav>
</header>
▶ Live Demo — ヘッダーナビゲーション
MyBrand

ここでのキーは justify-between です。これは justify-content: space-between に対応し、最初と最後のアイテムをコンテナの端に寄せ、残りを均等に分配します。ロゴとナビの間に「残り全部のスペース」が入るのがこのクラスの効果です。

Flexboxパターン② ― タグ・バッジの折り返し配置

タグやバッジなど「個数が可変で幅もバラバラ」な要素を並べるとき、flex-wrap が活躍します。Gridだと各アイテムの幅が均等になってしまうので、こういうケースはFlexの独壇場です。

タグの折り返し配置
<div class="flex flex-wrap gap-2">
  <span class="px-3 py-1 bg-cyan-100 text-cyan-800 text-xs font-medium rounded-full">
    Tailwind CSS
  </span>
  <span class="px-3 py-1 bg-cyan-100 text-cyan-800 text-xs font-medium rounded-full">
    レスポンシブ
  </span>
  <span class="px-3 py-1 bg-cyan-100 text-cyan-800 text-xs font-medium rounded-full">
    Flexbox
  </span>
  <!-- 幅が足りなくなったら自動で次の行へ -->
</div>
▶ Live Demo — タグの折り返し
Tailwind CSS レスポンシブ Flexbox Grid レイアウトパターン v4 ユーティリティファースト CSS設計

Flexboxパターン③ ― 上下中央揃えの万能パターン

「要素を親の中央にドンと置きたい」——CSSの永遠のテーマですよね。Tailwindなら flex items-center justify-center の3クラスで完了です。これ、覚えておくと本当に頻繁に使います。

完全中央配置
<!-- Flexbox で上下左右中央 -->
<div class="flex items-center justify-center h-64">
  <p>中央に配置されるコンテンツ</p>
</div>

<!-- Grid でも1クラスで可能(place-items) -->
<div class="grid place-items-center h-64">
  <p>こちらもセンタリングされます</p>
</div>
▶ Live Demo — 中央配置(Flex vs Grid)
FLEX
items-center justify-center
GRID
place-items-center
📌 ポイント
Gridの place-items-centeralign-items: centerjustify-items: center のショートハンドです。Flexよりクラス1つ少なくて済むので、「ただ中央に置くだけ」ならGridの方がスマート。ただしFlexは justify-betweengap との組み合わせが柔軟なので、複数要素を並べる場合はFlexに軍配が上がります。

Gridパターン ― カード一覧からBento Gridまで

CSS Gridの真骨頂は「行と列を同時にコントロールできる」こと。Tailwindの grid-cols-* ユーティリティを使えば、レスポンシブなカード一覧が信じられないほど短いコードで書けます。ここから4つの実践パターンを見ていきましょう。

パターン① 等幅カード一覧(レスポンシブ)

最も基本的なパターンです。前回のレスポンシブ記事でも触れましたが、ここではGridユーティリティの詳細に焦点を当てます。

レスポンシブカードグリッド
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
  <article class="bg-white rounded-xl p-6 shadow-sm">
    <h3 class="font-bold text-lg mb-2">タイトル</h3>
    <p class="text-gray-600 text-sm">説明文...</p>
  </article>
  <!-- 同様のカードを必要数繰り返す -->
</div>
▶ Live Demo — 等幅3カラムグリッド
Card Title 1
説明テキストがここに入ります。
Card Title 2
説明テキストがここに入ります。
Card Title 3
説明テキストがここに入ります。

grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 は「モバイルで1列、640px以上で2列、1024px以上で3列」という意味です。v4では grid-cols-<number> に任意の数値が使えるので、grid-cols-7 のような値も設定不要で動きます。

パターン② サイドバー + メインコンテンツ

管理画面やブログでお馴染みの「サイドバー固定幅 + メイン可変幅」レイアウト。Tailwindでは grid-cols-[<value>] のarbitrary value構文を使うと、自由なカラム定義ができます。

サイドバーレイアウト
<div class="grid grid-cols-[250px_1fr] gap-8 min-h-screen">
  <!-- サイドバー:固定250px -->
  <aside class="bg-gray-900 text-white p-6 rounded-xl">
    <nav class="flex flex-col gap-3">
      <a class="hover:text-cyan-400">Dashboard</a>
      <a class="hover:text-cyan-400">Projects</a>
      <a class="hover:text-cyan-400">Settings</a>
    </nav>
  </aside>

  <!-- メイン:残り全部 -->
  <main class="p-8">
    <h1 class="text-2xl font-bold">ダッシュボード</h1>
  </main>
</div>
▶ Live Demo — サイドバー + メイン
Dashboard
メインコンテンツがこの領域に入ります。サイドバーは固定幅、こちらは残り全幅(1fr)で伸縮します。
❌ やりがちなNG:Flexboxでサイドバーレイアウトを組む
<!-- Flexでも動くが、幅の制御が煩雑になりがち -->
<div class="flex">
  <aside class="w-[250px] flex-shrink-0">...</aside>
  <main class="flex-1 min-w-0">...</main>
</div>
<!-- flex-shrink-0 を忘れるとサイドバーが潰れる -->
<!-- min-w-0 を忘れるとメインがオーバーフローする -->
✅ Gridなら宣言的に定義できる
<div class="grid grid-cols-[250px_1fr] gap-8">
  <aside>...</aside>
  <main>...</main>
</div>
<!-- 列の幅がテンプレートで明示される。潰れる心配なし -->

パターン③ Holy Grailレイアウト

ヘッダー・フッター・サイドバー2本・メインエリアを持つ古典的なレイアウトですが、Gridで書くとたった数行で完成します。grid-rows-[auto_1fr_auto] がポイントで、ヘッダー/フッターは中身のサイズに合わせ、メインエリアが残りを全部取ります。

Holy Grail レイアウト
<div class="grid grid-cols-[200px_1fr_200px] grid-rows-[auto_1fr_auto] min-h-screen gap-4">
  <!-- ヘッダー:全列にまたがる -->
  <header class="col-span-3 bg-gray-900 text-white p-4">
    Header
  </header>

  <!-- 左サイドバー -->
  <aside class="bg-gray-100 p-4">Left</aside>

  <!-- メイン -->
  <main class="p-6">Main Content</main>

  <!-- 右サイドバー -->
  <aside class="bg-gray-100 p-4">Right</aside>

  <!-- フッター:全列にまたがる -->
  <footer class="col-span-3 bg-gray-900 text-white p-4">
    Footer
  </footer>
</div>
▶ Live Demo — Holy Grail Layout
Header (col-span-3)
Main Content Area
grid-cols-[200px_1fr_200px] と grid-rows-[auto_1fr_auto] で構成
Footer (col-span-3)

パターン④ Bento Grid(不揃いグリッド)

Apple風のBento Grid——大きなカードと小さなカードが混在するレイアウトが最近のトレンドです。col-span-*row-span-* を組み合わせるだけで実現できます。

Bento Grid レイアウト
<div class="grid grid-cols-4 grid-rows-3 gap-4">
  <!-- 大きいカード:2×2 -->
  <div class="col-span-2 row-span-2 bg-cyan-600 rounded-2xl p-8">
    Feature
  </div>

  <!-- 通常カード -->
  <div class="bg-gray-100 rounded-2xl p-6">Item A</div>
  <div class="bg-gray-100 rounded-2xl p-6">Item B</div>

  <!-- 横長カード:2×1 -->
  <div class="col-span-2 bg-gray-900 text-white rounded-2xl p-6">
    Wide Card
  </div>

  <!-- 残りのカード -->
  <div class="col-span-2 bg-gray-100 rounded-2xl p-6">Item C</div>
  <div class="col-span-2 bg-gray-100 rounded-2xl p-6">Item D</div>
</div>
▶ Live Demo — Bento Grid
Feature
col-span-2 row-span-2
A
B
Wide Card (col-span-2)
C (col-span-2)
D (col-span-2)
💡 現場の経験則
Bento Gridをレスポンシブ対応するときのコツ:モバイルでは grid-cols-1 にして全カードを1列に、タブレットで sm:grid-cols-2、デスクトップで lg:grid-cols-4 と段階的に増やします。col-span-* もブレイクポイント付きで lg:col-span-2 のように指定すれば、狭い画面では全幅、広い画面ではスパン付きになります。

Flex + Grid 合わせ技 ― 実務でよく出る複合パターン

実際のプロジェクトでは、FlexとGridを1つのページで混在させるのが当たり前です。ここでは「FlexとGridのどちらをどの階層で使うか」を意識した複合パターンを紹介します。

パターン⑤ カード内部のレイアウト(Grid × Flex)

カード一覧の「外枠」はGridで管理し、カードの「中身」はFlexboxで構成する——これが現場では最もよく使う組み合わせです。

Grid(外)+ Flex(中)の合わせ技
<!-- 外側:Grid で3列配置 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">

  <!-- カード1つ1つは Flex で中身を縦に並べる -->
  <article class="flex flex-col bg-white rounded-xl shadow-sm overflow-hidden">
    <img class="w-full h-48 object-cover" src="..." />
    <div class="flex flex-col flex-1 p-6">
      <h3 class="font-bold text-lg mb-2">記事タイトル</h3>
      <p class="text-gray-600 text-sm flex-1">本文の概要...</p>
      <!-- flex-1 で残りスペースを埋め、ボタンを下揃えに -->
      <a class="mt-4 text-cyan-600 text-sm font-bold">Read more →</a>
    </div>
  </article>

</div>
▶ Live Demo — カード内部のFlex配置
長めのタイトルが入るカード

ここは本文の概要です。テキスト量が多い場合でもボタンの位置が揃います。

Read more →
3枚目

高さが異なるカードでも "Read more" リンクが全部同じ位置に揃う。

Read more →

大事なのは flex flex-col flex-1 の組み合わせです。カードのボディ部分に flex-1 を付けることで高さが揃い、本文(pタグ)にも flex-1 を付けることで「Read more」リンクが常に下端に位置します。テキスト量がバラバラでもボタンの位置がガタつかない——これ、実務では非常に重宝します。

パターン⑥ スティッキーフッター(Flex版)

コンテンツが少ないページでもフッターが画面下部に張り付く「スティッキーフッター」。前回の導入記事でも触れましたが、あらためてパターンとして整理します。

スティッキーフッター
<body class="min-h-screen flex flex-col">
  <header class="...">ヘッダー</header>
  <main class="flex-1">メインコンテンツ</main>
  <footer class="...">フッター</footer>
</body>
<!-- min-h-screen + flex + flex-col + flex-1 が4点セット -->
▶ Live Demo — スティッキーフッター
Header

コンテンツが少なくてもフッターは下に張り付く。
main に flex-1 を付けるだけ。

© 2026 Footer — always at the bottom

応用テクニック ― auto-fitでカラム数を自動調整する

「画面幅に合わせてカラム数を自動で変えたい。ただし各カードの最小幅は250px」——こういうニーズ、レスポンシブカードの実装で本当によく出ます。ブレイクポイントを1つずつ指定する方法もいいんですが、auto-fitminmax() を使えば、ブレイクポイント定義なしで流体グリッドが完成します。

auto-fit + minmax() による流体グリッド
<div class="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-6">
  <div class="bg-white rounded-xl p-6 shadow-sm">Card 1</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">Card 2</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">Card 3</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">Card 4</div>
  <div class="bg-white rounded-xl p-6 shadow-sm">Card 5</div>
</div>
▶ Live Demo — auto-fit 流体グリッド(ブラウザ幅を変えてみてください)
Card 1
Card 2
Card 3
Card 4
Card 5

ポイントは grid-cols-[repeat(auto-fit,minmax(250px,1fr))] というarbitrary value構文です。これにより「最小250px、最大1fr」のカラムが画面幅に応じて自動で何列にもなります。ブレイクポイントを書かなくて済むので、カードの枚数が動的に変わるCMSサイトなどで特に効果的です。

⚠️ 注意
auto-fitauto-fill の違いを押さえておきましょう。auto-fitは「余ったスペースをカードが埋める(カードが伸びる)」。auto-fillは「余ったスペースは空カラムとして残る(カードの幅は最小値に固定)」。ほとんどの場合auto-fitの方が期待する動作ですが、カードを固定幅で左寄せにしたいときはauto-fillが正解です。

subgridで子要素の列を親に揃える

Tailwind CSS v4では grid-cols-subgrid がサポートされています。これは親グリッドのカラム定義を子要素がそのまま引き継ぐ機能で、カードの中身(タイトル行・本文行・フッター行)を隣のカードと横並びで揃えたいときに威力を発揮します。

subgrid で行の高さを揃える
<div class="grid grid-cols-3 gap-6">
  <!-- 各カードが親のグリッド行を参照 -->
  <article class="grid grid-rows-subgrid row-span-3 gap-2">
    <h3 class="font-bold">長いタイトルがここに入る場合でも</h3>
    <p class="text-sm text-gray-600">本文...</p>
    <a class="text-cyan-600 text-sm">Read more</a>
  </article>
  <!-- 他のカードも同じ構造 -->
</div>
▶ Live Demo — subgrid で行を揃える

短いタイトル

本文の概要テキスト。

Read more →

これは比較的長いタイトルが入るカード

本文も長め。タイトルの高さが違っても、本文とリンクの開始位置は隣と揃う。

Read more →

中くらい

subgridのおかげで全カードの各行が横方向に揃う。

Read more →

grid-rows-subgridrow-span-3 の組み合わせがキモです。各カードに「3行分のスペースを確保して、行の高さは親グリッドの定義を使う」と宣言することで、隣のカードとタイトル行・本文行・リンク行の位置が完全に揃います。従来は JavaScriptで高さを揃えたり、同じ高さのフェイクを作ったりと面倒だったこの問題が、CSSだけで解決できるようになりました。

よくあるミスと対処法

最後に、FlexboxやGridをTailwindで使うときに「あれ、思った通りにならない」と詰まりがちなポイントを整理しておきます。

ミス① flex-1 を付けたのに縮まない

❌ overflow が制御できない
<div class="flex">
  <div class="flex-1">
    <pre>ここに長いコードブロック...</pre>
  </div>
</div>
<!-- pre が親幅を突き破ってオーバーフローする -->
✅ min-w-0 を追加する
<div class="flex">
  <div class="flex-1 min-w-0">
    <pre class="overflow-x-auto">ここに長いコードブロック...</pre>
  </div>
</div>
<!-- min-w-0 で「デフォルトの min-width: auto」を打ち消す -->

Flexアイテムのデフォルト min-widthauto(コンテンツの最小サイズ以下には縮まない)です。min-w-0 を付けることで「0まで縮んでいいよ」と許可し、overflow-x-auto でスクロールさせるのが正攻法です。

ミス② gap と margin を混在させてスペースがおかしくなる

❌ gap とマージンを併用
<div class="flex gap-4">
  <div class="mr-4">A</div>  <!-- gap + mr-4 で余白が二重に -->
  <div>B</div>
  <div>C</div>
</div>
✅ gap に統一する
<div class="flex gap-4">
  <div>A</div>
  <div>B</div>
  <div>C</div>
</div>
<!-- Flex/Grid では gap で統一。margin は不要 -->

gap は「子要素間のスペース」を一括管理する機能なので、個別の margin と併用すると計算が複雑になります。Flex/Gridコンテナ内では基本的にgapだけでスペーシングを管理し、marginは「コンテナ自体の外側の余白」にだけ使う——これを鉄則にすると混乱が減ります。

ミス③ Grid で高さがバラバラになる

Gridアイテムはデフォルトで align-items: stretch(行の高さいっぱいに伸びる)ですが、カードの中身のテキスト量に差があると見た目がガタつくことがあります。解決策は2つです。

カードの高さ揃え ― 2つのアプローチ
<!-- 方法1: Flex + flex-1 で下揃え(先ほどのパターン⑤) -->
<article class="flex flex-col">
  <p class="flex-1">本文(伸びる)</p>
  <a>Read more(下に固定)</a>
</article>

<!-- 方法2: subgrid で隣のカードと行を共有(応用パターン) -->
<article class="grid grid-rows-subgrid row-span-3">
  <h3>タイトル</h3>
  <p>本文</p>
  <a>Read more</a>
</article>
📌 ポイント
実務でどちらを選ぶかの基準:カードの内部構造がシンプル(2〜3要素)なら flex + flex-1 で十分。カードの中身が多階層で「タイトル行は揃えたいけど画像の高さは可変」のような要件なら subgrid の出番です。2025年以降、subgrid のブラウザサポートは全モダンブラウザで安定しているので安心して使えます。

まとめ

  • Flexboxは「1次元の配置」、Gridは「2次元のレイアウト設計」——子要素が均等幅で並ぶならGrid、幅がバラバラならFlexが自然な選択肢
  • ナビバーやタグの折り返し配置など、要素数が可変で幅が不揃いなUIにはFlexbox + flex-wrap + gap の3点セットが最適
  • サイドバーやHoly Grailなど「列幅を明示的に定義したい」レイアウトは grid-cols-[250px_1fr] のようなarbitrary value構文でGridを使う
  • Bento Gridは col-span-* と row-span-* の組み合わせで実現。レスポンシブ対応はブレイクポイント付き col-span で段階的に変化させる
  • カード一覧は「外側Grid + 内側Flex」が鉄板パターン。flex-1で本文を伸ばし、ボタン位置を下端に固定する
  • auto-fit + minmax() を使えば、ブレイクポイント不要の流体グリッドが作れる。カード枚数が動的なCMS案件に特に有効
  • subgrid で親グリッドの行定義を子に継承させれば、隣同士のカードでタイトル行・本文行の位置を完全に揃えられる