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

FlexboxとGrid、どう使い分ける?
「カードを3列に並べたい」——こんなとき、あなたは flex と grid のどちらを選びますか? どちらでも実現はできるけど、「自然で壊れにくい方」はテーマによって違います。ざっくりした判断基準を最初に整理しておきましょう。
Flexboxは「1次元(横 or 縦の1列)のコンテンツ配置」が得意です。ナビゲーション、ボタンの横並び、テキストとアイコンの位置合わせなど、「1行のなかで柔軟に配置する」場面で真価を発揮します。一方Gridは「2次元(行 × 列)のレイアウト設計」が本領。カード一覧、ダッシュボード、雑誌風のレイアウトなど、「面」で設計するときに圧倒的に強い。
現場でのポイントは「子要素の数や幅が予測しにくい → Flex」「行と列を同時にコントロールしたい → Grid」という判断です。もちろん組み合わせて使うことも多く、Grid全体レイアウトの中にFlexのナビバーが入る……というのが実際のコード構造です。
<!-- 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>
FLEXBOX — 子要素のサイズに合わせて伸縮
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>
ここでのキーは 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>
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>
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>
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>
<!-- 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 を忘れるとメインがオーバーフローする -->
<div class="grid grid-cols-[250px_1fr] gap-8">
<aside>...</aside>
<main>...</main>
</div>
<!-- 列の幅がテンプレートで明示される。潰れる心配なし -->
パターン③ Holy Grailレイアウト
ヘッダー・フッター・サイドバー2本・メインエリアを持つ古典的なレイアウトですが、Gridで書くとたった数行で完成します。grid-rows-[auto_1fr_auto] がポイントで、ヘッダー/フッターは中身のサイズに合わせ、メインエリアが残りを全部取ります。
<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>
パターン④ Bento Grid(不揃いグリッド)
Apple風のBento Grid——大きなカードと小さなカードが混在するレイアウトが最近のトレンドです。col-span-* と row-span-* を組み合わせるだけで実現できます。
<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>
Flex + Grid 合わせ技 ― 実務でよく出る複合パターン
実際のプロジェクトでは、FlexとGridを1つのページで混在させるのが当たり前です。ここでは「FlexとGridのどちらをどの階層で使うか」を意識した複合パターンを紹介します。
パターン⑤ カード内部のレイアウト(Grid × Flex)
カード一覧の「外枠」はGridで管理し、カードの「中身」はFlexboxで構成する——これが現場では最もよく使う組み合わせです。
<!-- 外側: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>
大事なのは 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点セット -->
応用テクニック ― auto-fitでカラム数を自動調整する
「画面幅に合わせてカラム数を自動で変えたい。ただし各カードの最小幅は250px」——こういうニーズ、レスポンシブカードの実装で本当によく出ます。ブレイクポイントを1つずつ指定する方法もいいんですが、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>
ポイントは grid-cols-[repeat(auto-fit,minmax(250px,1fr))] というarbitrary value構文です。これにより「最小250px、最大1fr」のカラムが画面幅に応じて自動で何列にもなります。ブレイクポイントを書かなくて済むので、カードの枚数が動的に変わるCMSサイトなどで特に効果的です。
subgridで子要素の列を親に揃える
Tailwind CSS v4では grid-cols-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>
短いタイトル
本文の概要テキスト。
Read more →これは比較的長いタイトルが入るカード
本文も長め。タイトルの高さが違っても、本文とリンクの開始位置は隣と揃う。
Read more →中くらい
subgridのおかげで全カードの各行が横方向に揃う。
Read more →grid-rows-subgrid と row-span-3 の組み合わせがキモです。各カードに「3行分のスペースを確保して、行の高さは親グリッドの定義を使う」と宣言することで、隣のカードとタイトル行・本文行・リンク行の位置が完全に揃います。従来は JavaScriptで高さを揃えたり、同じ高さのフェイクを作ったりと面倒だったこの問題が、CSSだけで解決できるようになりました。
よくあるミスと対処法
最後に、FlexboxやGridをTailwindで使うときに「あれ、思った通りにならない」と詰まりがちなポイントを整理しておきます。
ミス① flex-1 を付けたのに縮まない
<div class="flex">
<div class="flex-1">
<pre>ここに長いコードブロック...</pre>
</div>
</div>
<!-- pre が親幅を突き破ってオーバーフローする -->
<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-width は auto(コンテンツの最小サイズ以下には縮まない)です。min-w-0 を付けることで「0まで縮んでいいよ」と許可し、overflow-x-auto でスクロールさせるのが正攻法です。
ミス② gap と margin を混在させてスペースがおかしくなる
<div class="flex gap-4">
<div class="mr-4">A</div> <!-- gap + mr-4 で余白が二重に -->
<div>B</div>
<div>C</div>
</div>
<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つです。
<!-- 方法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>
まとめ
- 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 で親グリッドの行定義を子に継承させれば、隣同士のカードでタイトル行・本文行の位置を完全に揃えられる