CSS FlexboxとGrid:どちらを使うべきか

· 12分で読めます

目次

CSS FlexboxとGridのどちらを選ぶかは、特に両方とも同じレイアウト問題を解決できるように見える場合、圧倒されるように感じることがあります。実際には、それぞれ異なる目的のために設計されており、その強みを理解することで、より効果的な開発者になれます。

このガイドでは、FlexboxとGridについて、基本概念から実際のアプリケーションまで、知っておくべきすべてを解説します。最後には、どのレイアウトシナリオでどのツールを使うべきか正確に分かるようになります。

Flexboxの基本(1次元レイアウト)

Flexboxは1次元レイアウト用に設計されています — アイテムを単一の行または列に配置します。1つの軸に沿ってスペースを分配し、アイテムを整列させることに優れており、ナビゲーションバー、ボタングループ、単一方向に流れるコンテンツに最適です。

コアコンセプト

すべてのFlexboxレイアウトにはフレックスコンテナ(親)とフレックスアイテム(子)があります。コンテナはアイテムの方向、折り返し、整列を制御します:

/* フレックスコンテナ */
.container {
  display: flex;
  flex-direction: row;      /* row | row-reverse | column | column-reverse */
  justify-content: center;  /* 主軸の整列 */
  align-items: center;      /* 交差軸の整列 */
  gap: 1rem;                /* アイテム間のスペース */
  flex-wrap: wrap;          /* アイテムを次の行に折り返すことを許可 */
}

/* フレックスアイテム */
.item {
  flex: 1;                  /* 利用可能なスペースを埋めるために成長 */
  /* 省略形: flex-grow: 1; flex-shrink: 1; flex-basis: 0; */
}

.item-fixed {
  flex: 0 0 200px;          /* 成長しない、縮小しない、200px幅 */
}

主軸と交差軸の理解

Flexboxをマスターする鍵は、2つの軸を理解することです。主軸flex-directionで設定された方向に走ります(rowの場合は水平、columnの場合は垂直)。交差軸はそれに垂直に走ります。

この軸システムは、どのプロパティがどの次元を制御するかを決定します。justify-contentは常に主軸で機能し、align-itemsは交差軸で機能します。

整列プロパティ

/* 主軸(row方向では水平) */
.container {
  justify-content: flex-start;   /* デフォルト: アイテムを開始位置に詰める */
  justify-content: flex-end;     /* アイテムを終了位置に詰める */
  justify-content: center;       /* アイテムを中央に配置 */
  justify-content: space-between;/* アイテム間に均等なスペース */
  justify-content: space-around; /* アイテムの周りに均等なスペース */
  justify-content: space-evenly; /* すべての場所に均等なスペース */
}

/* 交差軸(row方向では垂直) */
.container {
  align-items: stretch;    /* デフォルト: コンテナを埋めるように伸ばす */
  align-items: flex-start; /* 上に整列 */
  align-items: flex-end;   /* 下に整列 */
  align-items: center;     /* 垂直方向に中央配置 */
  align-items: baseline;   /* テキストのベースラインを整列 */
}

flexプロパティの説明

flexプロパティは3つのプロパティの省略形です:flex-growflex-shrinkflex-basis。これらを個別に理解することで、より正確なレイアウトを書くことができます。

.item-grow {
  flex: 1;        /* 次と同等: 1 1 0% */
}

.item-fixed {
  flex: 0 0 200px; /* 成長も縮小もしない、200pxを維持 */
}

.item-shrink {
  flex: 0 1 auto;  /* 成長しないが、必要に応じて縮小可能 */
}

プロのヒント: アイテムにスペースを均等に共有させたい場合はflex: 1を使用し、アイテムを成長または縮小させずに自然なサイズを維持したい場合はflex: 0 0 autoを使用します。

Gridの基本(2次元レイアウト)

CSS Gridは2次元レイアウト用に構築されています — 行と列の両方を同時に制御します。ページレベルのレイアウト、カードグリッド、両方の次元で正確な制御が必要なデザインに最適な選択肢です。

コアコンセプト

Gridレイアウトはグリッドコンテナグリッドアイテムで構成されます。Flexboxとは異なり、Gridでは明示的なトラック(行と列)を定義し、その構造内の任意の場所にアイテムを配置できます:

/* グリッドコンテナ */
.container {
  display: grid;
  grid-template-columns: 200px 1fr 1fr;  /* 3列 */
  grid-template-rows: auto 1fr auto;     /* 3行 */
  gap: 1rem;                             /* セル間のスペース */
  grid-auto-flow: row;                   /* 自動配置されたアイテムの流れ方 */
}

/* グリッドアイテム */
.item {
  grid-column: 1 / 3;    /* 列ライン1から3までスパン */
  grid-row: 1 / 2;       /* 最初の行を占有 */
}

.item-area {
  grid-area: header;     /* 名前付きエリアに配置 */
}

グリッドラインとトラックの理解

Gridはトラック間に番号付きラインを作成します。3列のグリッドには4本の垂直ライン(1、2、3、4)があります。アイテムは、どのライン間にスパンするかを指定することで配置されます。

トラックはライン間のスペースです — 実際の列と行です。固定単位(px)、柔軟な単位(fr)、またはコンテンツベースのサイズ(auto、min-content、max-content)でサイズを設定できます。

FR単位

fr単位はGridのスーパーパワーです。利用可能なスペースの分数を表し、トラック間で比例的に分配します:

.container {
  grid-template-columns: 1fr 2fr 1fr;  /* 中央の列が2倍のスペースを取得 */
  grid-template-columns: 200px 1fr;    /* 固定サイドバー、柔軟なコンテンツ */
  grid-template-columns: repeat(3, 1fr); /* 3つの等しい列 */
}

名前付きグリッドエリア

Gridのテンプレートエリア機能を使用すると、ASCIIアートのような構文を使用してレイアウトを作成でき、複雑なレイアウトを読みやすくします:

.container {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar content content"
    "footer footer footer";
  grid-template-columns: 200px 1fr 1fr;
  grid-template-rows: auto 1fr auto;
}

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

自動配置とグリッド自動フロー

Gridは、明示的に配置しないアイテムを自動的に配置できます。grid-auto-flowプロパティは、アイテムが行を先に埋めるか(デフォルト)、列を先に埋めるかを制御します:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-flow: dense;  /* 小さいアイテムで隙間を埋める */
}

プロのヒント: 隙間を埋めたいメイソンリー風のレイアウトにはgrid-auto-flow: denseを使用しますが、これによりアイテムの視覚的な順序が変わる可能性があり、アクセシビリティに影響を与える可能性があることに注意してください。

並列比較

FlexboxとGridを主要な次元で比較して、その基本的な違いを理解しましょう:

機能 Flexbox Grid
次元性 1次元(行または列) 2次元(行と列)
コンテンツ駆動 はい - アイテムがサイズを制御 いいえ - コンテナが構造を定義
レイアウト方向 一度に単一の軸 両方の軸を同時に
アイテムの配置 順次(ソース順) 明示的な配置が可能
整列 単一軸で強力 両方の軸で強力
gapサポート はい(モダンブラウザ) はい(最初から)
最適な用途 コンポーネント、ナビゲーション、ツールバー ページレイアウト、カードグリッド、ダッシュボード
学習曲線 中程度 最初は急

概念的な違い

基本的な違いは制御に帰着します。Flexboxはコンテンツアウトです — アイテムはコンテンツサイズに基づいてレイアウトに影響を与えます。Gridはレイアウトインです — 最初に構造を定義し、その後コンテンツを配置します。

Flexboxは測定しているものに合わせて調整する柔軟な定規のようなものと考えてください。Gridは、最初に構造を決定する方眼紙のようなものです。

シナリオ Flexboxアプローチ Gridアプローチ
ナビゲーションバー 自然にフィット - 行内のアイテム 過剰 - 構造が多すぎる
カードグリッド 可能だが折り返しが不自然 完璧 - 明示的な行と列
フォームレイアウト シンプルなフォームに適している 複雑な複数列フォームに適している
ページレイアウト 複数のコンテナのネストが必要 単一のコンテナで処理可能
コンテンツの中央配置 優れている - シンプルで直感的 同様に優れている - place-items: center

Flexboxを使うべき場合

Flexboxは、コンテンツが単一方向に流れ、アイテムが利用可能なスペースに適応する必要があるシナリオで輝きます。Flexboxが最適な選択肢となる状況は次のとおりです:

ナビゲーションバーとメニュー

ナビゲーションコンポーネントはFlexboxの代表例です。アイテムは自然に行に流れ、スペースを均等に分配したり、反対側の端に整列させたりすることがよくあります:

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
}

.nav-links {
  display: flex;
  gap: 2rem;
  list-style: none;
}

ボタングループとツールバー

横に並べるべきボタンやツールのコレクションがある場合、Flexboxは間隔と整列を完璧に処理します:

.button-group {
  display: flex;
  gap: 0.5rem;
}

.toolbar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 1rem;
}

メディアオブジェクト

古典的なメディアオブジェクトパターン(片側に画像、もう片側にコンテンツ)は、Flexboxで簡単です:

.media {
  display: flex;
  gap: 1rem;
}

.media-image {
  flex: 0 0 100px;  /* 固定幅の画像 */
}

.media-content {
  flex: 1;  /* コンテンツが残りのスペースを取る */
}

フォームコントロール

ラベル、入力、ボタンが行に並ぶ入力グループは、Flexboxに最適です:

.input-group {
  display: flex;
  gap: 0.5rem;
}

.input-group input {
  flex: 1;  /* 入力がスペースを埋めるために成長 */
}

.input-group button {
  flex: 0 0 auto;  /* ボタンは自然なサイズを維持 */
}

垂直方向の中央配置