はじめに

モダンCSSでレイアウトを構築する際、FlexboxとCSS Gridという2つの強力なツールを選択できます。しかし、「どちらを使えばよいのか」「併用しても問題ないのか」という疑問を持つ方は少なくありません。

結論から言えば、FlexboxとCSS Gridは競合するものではなく、それぞれ異なる得意分野を持つ相互補完的なレイアウト手法です。適切な場面で適切なツールを選択することで、保守性の高いCSSを効率的に記述できます。

本記事では、FlexboxとCSS Gridの使い分けについて以下の内容を解説します。

  • FlexboxとCSS Gridの根本的な違い(1次元 vs 2次元)
  • それぞれが得意なレイアウトパターン
  • 選択の判断基準となる5つのチェックポイント
  • FlexboxとGridを組み合わせる実践パターン
  • よくある設計ミスと改善方法

前提条件

本記事を読み進めるにあたり、以下の知識があることを前提としています。

  • Flexboxの基本概念(フレックスコンテナ・フレックスアイテム・主軸・交差軸)
  • CSS Gridの基本概念(グリッドコンテナ・グリッドアイテム・トラック・ライン)
  • justify-contentalign-itemsなどの配置プロパティ

これらの基礎知識については、以下の記事で解説しています。

動作確認環境

  • Google Chrome 131以降
  • Firefox 133以降
  • Safari 18以降
  • Microsoft Edge 131以降

FlexboxとCSS Gridの根本的な違い

FlexboxとCSS Gridの最も重要な違いは「次元」です。この概念を正確に理解することが、適切な使い分けの第一歩となります。

1次元レイアウト: Flexbox

Flexboxは1次元レイアウトを制御するために設計されています。これは、行(横方向)か列(縦方向)のいずれか一方向にアイテムを配置することを意味します。

1
2
3
4
5
6
/* Flexbox: 横一列に配置 */
.flex-container {
  display: flex;
  flex-direction: row;  /* 主軸は横方向 */
  gap: 16px;
}

Flexboxでは、アイテムの配置は主軸に沿って行われます。折り返し(flex-wrap: wrap)を使用した場合でも、各行は独立して制御され、行間の列位置は揃いません。

2次元レイアウト: CSS Grid

CSS Gridは2次元レイアウトを制御するために設計されています。これは、行(横方向)と列(縦方向)の両方を同時に制御することを意味します。

1
2
3
4
5
6
7
/* CSS Grid: 行と列を同時に定義 */
.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);  /* 3列 */
  grid-template-rows: auto auto;          /* 2行 */
  gap: 16px;
}

CSS Gridでは、明示的にトラック(行と列)を定義し、アイテムをグリッドセル上に配置します。行間でも列位置が揃い、整然としたグリッドレイアウトを実現できます。

視覚的な違いを理解する

以下の図は、同じ5つのアイテムをFlexboxとCSS Gridでそれぞれ配置した場合の違いを示しています。

flowchart TB
    subgraph flexbox["Flexbox(flex-wrap: wrap)"]
        direction LR
        subgraph row1["Row 1"]
            F1["Item 1<br/>幅:200px"]
            F2["Item 2<br/>幅:150px"]
            F3["Item 3<br/>幅:180px"]
        end
        subgraph row2["Row 2"]
            F4["Item 4<br/>幅:220px"]
            F5["Item 5<br/>幅:160px"]
        end
    end
    
    subgraph grid["CSS Grid(3列グリッド)"]
        direction TB
        subgraph grow1["Row 1"]
            G1["Item 1"]
            G2["Item 2"]
            G3["Item 3"]
        end
        subgraph grow2["Row 2"]
            G4["Item 4"]
            G5["Item 5"]
            G6[" "]
        end
    end

Flexboxの特徴:

  • 各アイテムのコンテンツに応じてサイズが決まる(コンテンツファースト)
  • 行間で列位置が揃わない
  • アイテム数に応じて柔軟に配置される

CSS Gridの特徴:

  • グリッドトラックのサイズが先に決まる(レイアウトファースト)
  • 行間で列位置が揃う
  • 空のセルが生じることがある

それぞれが得意なレイアウトパターン

FlexboxとCSS Gridには、それぞれ得意とするレイアウトパターンがあります。具体例を通じて理解を深めましょう。

Flexboxが得意なパターン

パターン1: ナビゲーションバー

ナビゲーションバーは典型的な1次元レイアウトです。メニュー項目を横一列に並べ、ロゴとメニューの間にスペースを入れるといった配置はFlexboxの得意分野です。

1
2
3
4
5
6
7
8
9
<nav class="navbar">
  <div class="logo">Logo</div>
  <ul class="menu">
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Services</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
}

.menu {
  display: flex;
  gap: 24px;
  list-style: none;
  margin: 0;
  padding: 0;
}

Flexboxを選ぶ理由:

  • 横一列に並べるだけの1次元レイアウト
  • space-betweenで左右に振り分ける配置が容易
  • メニュー項目数が変動してもレイアウトが崩れない

パターン2: カードのコンテンツ配置

カード内部のレイアウト(画像・タイトル・説明文・ボタン)は、縦方向の1次元レイアウトです。

1
2
3
4
5
6
7
8
<article class="card">
  <img src="image.jpg" alt="Card image" class="card-image">
  <div class="card-content">
    <h3 class="card-title">Card Title</h3>
    <p class="card-description">Description text goes here...</p>
  </div>
  <button class="card-button">Read More</button>
</article>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.card-content {
  flex: 1;  /* 残りの空間を埋める */
}

.card-button {
  margin-top: auto;  /* 最下部に配置 */
}

Flexboxを選ぶ理由:

  • 縦一列の1次元レイアウト
  • flex: 1margin-top: autoでコンテンツ量に関わらずボタンを最下部に固定
  • カードの高さが揃う際に内部コンテンツが柔軟に対応

パターン3: センタリング

要素を水平・垂直方向に中央揃えするケースは、Flexboxが最もシンプルに書けます。

1
2
3
4
5
6
.center-container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

Flexboxを選ぶ理由:

  • たった3行で完全なセンタリングを実現
  • 中央に配置する要素が1つの場合に最適

パターン4: 入力フォームのインライン配置

ラベル、入力フィールド、ボタンを横一列に並べるフォームレイアウトです。

1
2
3
4
5
<form class="search-form">
  <label for="search" class="visually-hidden">検索</label>
  <input type="text" id="search" class="search-input" placeholder="キーワードを入力">
  <button type="submit" class="search-button">検索</button>
</form>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.search-form {
  display: flex;
  gap: 8px;
}

.search-input {
  flex: 1;  /* 残りの幅を埋める */
  padding: 8px 12px;
}

.search-button {
  flex-shrink: 0;  /* ボタンは縮小しない */
  padding: 8px 16px;
}

Flexboxを選ぶ理由:

  • 横一列の1次元レイアウト
  • 入力フィールドをflex: 1で伸縮させ、ボタンは固定幅を維持

CSS Gridが得意なパターン

パターン1: ページ全体のレイアウト

ヘッダー、サイドバー、メインコンテンツ、フッターで構成されるページレイアウトは、CSS Gridの代表的なユースケースです。

1
2
3
4
5
6
<div class="page-layout">
  <header class="header">Header</header>
  <nav class="sidebar">Sidebar</nav>
  <main class="main">Main Content</main>
  <footer class="footer">Footer</footer>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
.page-layout {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  min-height: 100vh;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }

CSS Gridを選ぶ理由:

  • 行と列を同時に制御する2次元レイアウト
  • grid-template-areasで視覚的にレイアウトを定義可能
  • 各エリアのサイズと位置を明示的に指定

パターン2: 画像ギャラリー

画像を格子状に整列させるギャラリーは、CSS Gridが最適です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
}

.gallery-item {
  aspect-ratio: 1 / 1;
  overflow: hidden;
}

.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

CSS Gridを選ぶ理由:

  • 全ての画像を同じサイズのセルに配置
  • auto-fillminmax()でレスポンシブに列数を調整
  • 行間で列位置が完全に揃う

パターン3: ダッシュボードUI

複数のウィジェットを配置するダッシュボードは、2次元的なレイアウト制御が必要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto;
  gap: 24px;
}

.widget-large {
  grid-column: span 2;
  grid-row: span 2;
}

.widget-wide {
  grid-column: span 2;
}

.widget-tall {
  grid-row: span 2;
}

CSS Gridを選ぶ理由:

  • 各ウィジェットが異なるサイズ(2列分、2行分など)を占める
  • グリッドライン上に正確に配置
  • 後からウィジェットの位置を変更しやすい

パターン4: フォームレイアウト

ラベルと入力フィールドを2列で整列させるフォームは、CSS Gridが適しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<form class="form-grid">
  <label for="name">名前</label>
  <input type="text" id="name">
  
  <label for="email">メールアドレス</label>
  <input type="email" id="email">
  
  <label for="message">メッセージ</label>
  <textarea id="message" rows="4"></textarea>
</form>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
.form-grid {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 16px 24px;
  align-items: start;
}

.form-grid label {
  text-align: right;
  padding-top: 8px;
}

CSS Gridを選ぶ理由:

  • ラベル列と入力列の幅を明示的に定義
  • 全てのラベルが同じ幅で右揃え
  • 行を追加してもレイアウトが維持される

選択の判断基準: 5つのチェックポイント

どちらを使うべきか迷った場合は、以下の5つのチェックポイントに従って判断してください。

チェックポイント1: 制御したい次元は1つか2つか

最も重要な判断基準です。

制御したい次元 推奨レイアウト手法
行または列のいずれか一方 Flexbox
行と列の両方を同時に CSS Grid
flowchart TD
    A["レイアウト要件を分析"] --> B{"行と列を<br/>同時に制御する必要がある?"}
    B -->|はい| C["CSS Gridを選択"]
    B -->|いいえ| D{"要素を横一列または<br/>縦一列に並べる?"}
    D -->|はい| E["Flexboxを選択"]
    D -->|いいえ| F["要件を再分析"]

チェックポイント2: コンテンツファーストかレイアウトファーストか

コンテンツファースト(Flexbox):

  • コンテンツのサイズに応じてレイアウトを決める
  • 「このナビゲーション項目がいくつあっても均等に配置したい」
  • 「テキストの長さに応じてカラム幅を調整したい」

レイアウトファースト(CSS Grid):

  • 先にレイアウト(列数・行数・サイズ)を決め、そこにコンテンツを配置する
  • 「3列のグリッドを作り、各セルに画像を配置したい」
  • 「サイドバーは250px固定、メインコンテンツは残り全部」

チェックポイント3: 行間で列位置を揃える必要があるか

揃える必要がある場合: CSS Grid

1
2
3
4
5
/* 行間で列が揃う */
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

揃える必要がない場合: Flexbox

1
2
3
4
5
/* 各行は独立して配置される */
.flex {
  display: flex;
  flex-wrap: wrap;
}

チェックポイント4: 配置がアイテムの順序に依存するか

順序に依存する場合: Flexbox

  • アイテムは自然な順序で流れるように配置される
  • 追加されたアイテムは末尾に配置される

順序に依存しない場合: CSS Grid

  • grid-columngrid-rowで任意の位置に配置可能
  • アイテムをグリッド上の特定のセルに直接配置

チェックポイント5: 空のスペースをどう扱うか

空のスペースをアイテム間に分配: Flexbox

1
2
3
4
.flex {
  display: flex;
  justify-content: space-between; /* 余白を均等に分配 */
}

空のセルをそのまま維持: CSS Grid

1
2
3
4
5
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* 3つのアイテムなら埋まるが、2つなら1セル空く */
}

FlexboxとGridを組み合わせる実践パターン

実際のWebサイトでは、FlexboxとCSS Gridを組み合わせて使用することが一般的です。ページ全体はGridで構成し、個々のコンポーネント内部はFlexboxで制御するアプローチが効果的です。

パターン1: Gridレイアウト + Flexboxカード

ページ全体をCSS Gridで構成し、各カードの内部はFlexboxで制御します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<section class="card-section">
  <article class="card">
    <img src="image1.jpg" alt="" class="card-image">
    <div class="card-body">
      <h3 class="card-title">Card Title 1</h3>
      <p class="card-text">Description...</p>
    </div>
    <a href="#" class="card-link">Read More</a>
  </article>
  <!-- 他のカードも同様 -->
</section>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* 外側のレイアウト: CSS Grid */
.card-section {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
}

/* カード内部のレイアウト: Flexbox */
.card {
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.card-body {
  flex: 1;
  padding: 16px;
}

.card-link {
  margin-top: auto;
  padding: 16px;
  text-align: center;
  background: #f5f5f5;
}

組み合わせの利点:

  • CSS Grid: カードを格子状に整列させ、レスポンシブに列数を調整
  • Flexbox: カードの高さが揃った状態で、内部コンテンツを柔軟に配置
flowchart TB
    subgraph page["ページ構造"]
        subgraph grid["CSS Grid(カードの配置)"]
            subgraph card1["Card 1"]
                direction TB
                C1I["Image"]
                C1B["Body<br/>flex: 1"]
                C1L["Link"]
            end
            subgraph card2["Card 2"]
                direction TB
                C2I["Image"]
                C2B["Body<br/>flex: 1"]
                C2L["Link"]
            end
            subgraph card3["Card 3"]
                direction TB
                C3I["Image"]
                C3B["Body<br/>flex: 1"]
                C3L["Link"]
            end
        end
    end
    
    style card1 fill:#e3f2fd
    style card2 fill:#e3f2fd
    style card3 fill:#e3f2fd

パターン2: Gridページレイアウト + Flexboxヘッダー

ページ全体のレイアウトはCSS Gridで、ヘッダー内部のナビゲーションはFlexboxで制御します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<div class="page">
  <header class="header">
    <div class="logo">Logo</div>
    <nav class="nav">
      <a href="#">Home</a>
      <a href="#">About</a>
      <a href="#">Contact</a>
    </nav>
  </header>
  <aside class="sidebar">Sidebar</aside>
  <main class="main">Main Content</main>
  <footer class="footer">Footer</footer>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* ページ全体: CSS Grid */
.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  min-height: 100vh;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }

/* ヘッダー内部: Flexbox */
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
  background: #1a1a1a;
  color: #fff;
}

.nav {
  display: flex;
  gap: 24px;
}

.nav a {
  color: #fff;
  text-decoration: none;
}

パターン3: ネストしたGridとFlexbox

複雑なダッシュボードUIでは、複数レベルでGridとFlexboxを組み合わせます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* ダッシュボード全体: Grid */
.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
}

/* ウィジェット: Gridで位置とサイズを制御 */
.widget-stats {
  grid-column: span 2;
  display: flex;  /* 内部はFlexbox */
  justify-content: space-around;
  align-items: center;
  padding: 24px;
  background: #fff;
  border-radius: 8px;
}

/* ウィジェット内の個別統計: Flexbox */
.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

/* チャートウィジェット: 内部でGridを再利用 */
.widget-chart {
  grid-column: span 2;
  grid-row: span 2;
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 16px;
  padding: 24px;
  background: #fff;
  border-radius: 8px;
}

よくある設計ミスと改善方法

ミス1: 2次元レイアウトをFlexboxで無理に実現

問題のあるコード:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* 3列グリッドをFlexboxで模倣 */
.card-container {
  display: flex;
  flex-wrap: wrap;
}

.card {
  flex: 0 0 calc(33.333% - 16px);
  margin: 8px;
}

問題点:

  • 計算式が複雑でメンテナンスしにくい
  • 最終行のアイテムが3つ未満の場合、意図しない配置になる
  • ガター(間隔)の調整が難しい

改善したコード:

1
2
3
4
5
.card-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

ミス2: 単純な横並びにCSS Gridを使用

問題のあるコード:

1
2
3
4
5
6
/* ナビゲーションをGridで実装 */
.nav {
  display: grid;
  grid-template-columns: repeat(4, auto);
  gap: 24px;
}

問題点:

  • ナビゲーション項目数が変わるとgrid-template-columnsも変更が必要
  • 単純な横並びにはGridは冗長

改善したコード:

1
2
3
4
.nav {
  display: flex;
  gap: 24px;
}

ミス3: FlexboxとGridの混在による意図しない挙動

問題のあるコード:

1
2
3
4
.container {
  display: flex;
  display: grid;  /* 後から記述したgridが適用される */
}

改善方針:

  • 1つの要素に対してFlexboxかGridのいずれか1つだけを適用する
  • 異なるレイアウト手法が必要な場合は、ラッパー要素を追加する

ミス4: レスポンシブ対応の不足

問題のあるコード:

1
2
3
4
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr); /* 常に4列固定 */
}

改善したコード:

1
2
3
4
5
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 24px;
}

判断フローチャート

どちらを使うべきか迷った場合は、以下のフローチャートに従って判断してください。

flowchart TD
    Start["レイアウト要件を確認"] --> Q1{"行と列の両方を<br/>同時に制御する?"}
    
    Q1 -->|はい| Grid1["CSS Grid"]
    Q1 -->|いいえ| Q2{"要素を一方向に<br/>並べるだけ?"}
    
    Q2 -->|はい| Flex1["Flexbox"]
    Q2 -->|いいえ| Q3{"行間で列位置を<br/>揃える必要がある?"}
    
    Q3 -->|はい| Grid2["CSS Grid"]
    Q3 -->|いいえ| Q4{"コンテンツのサイズに<br/>応じてレイアウトを<br/>調整する?"}
    
    Q4 -->|はい| Flex2["Flexbox"]
    Q4 -->|いいえ| Q5{"レイアウトを先に決めて<br/>コンテンツを配置する?"}
    
    Q5 -->|はい| Grid3["CSS Grid"]
    Q5 -->|いいえ| Flex3["Flexbox"]
    
    Grid1 --> Result1["grid-template-areas<br/>grid-template-columns<br/>grid-template-rows"]
    Grid2 --> Result2["repeat + auto-fill/fit<br/>minmax()"]
    Grid3 --> Result3["明示的なトラック定義"]
    
    Flex1 --> Result4["flex-direction<br/>justify-content<br/>align-items"]
    Flex2 --> Result5["flex-grow<br/>flex-shrink<br/>flex-basis"]
    Flex3 --> Result6["gap + flex-wrap"]

まとめ

FlexboxとCSS Gridは、それぞれ異なる強みを持つレイアウト手法です。以下のポイントを押さえて、適切に使い分けましょう。

比較項目 Flexbox CSS Grid
次元 1次元(行または列) 2次元(行と列)
設計思想 コンテンツファースト レイアウトファースト
得意なレイアウト ナビゲーション、センタリング、カード内部 ページレイアウト、ギャラリー、ダッシュボード
アイテムサイズ コンテンツに依存 トラック定義に依存
行間の列揃え 揃わない(各行独立) 揃う

選択の基本指針:

  1. 1次元レイアウト(横一列・縦一列) → Flexbox
  2. 2次元レイアウト(行と列を同時制御) → CSS Grid
  3. コンテンツ量に応じた柔軟な配置 → Flexbox
  4. 事前に決めたレイアウトへの配置 → CSS Grid
  5. 両者を組み合わせる → ページ全体はGrid、コンポーネント内部はFlex

実際のWebサイト開発では、FlexboxとCSS Gridを適材適所で組み合わせることが一般的です。それぞれの特性を理解し、レイアウト要件に応じて最適な手法を選択してください。

参考リンク