はじめに

Flexboxでレイアウトを構築する際、「余ったスペースをどう分配するか」「コンテナに収まらない場合にどう縮小するか」「アイテムの初期サイズをどう決めるか」といった課題に直面します。これらを制御するのがflex-growflex-shrinkflex-basisの3つのプロパティです。

本記事では、Flexアイテムのサイズ制御について以下の内容を解説します。

  • flex-growによる余白の分配メカニズム
  • flex-shrinkによる縮小比率の制御
  • flex-basisによる基準サイズの設定
  • flexショートハンドの書き方と推奨値
  • 実務で使える具体的なパターン

これらのプロパティを正しく理解することで、あらゆる画面サイズに対応する柔軟なレイアウトを実装できるようになります。

前提条件

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

  • Flexboxの基本概念(フレックスコンテナとフレックスアイテム)
  • 主軸(main axis)と交差軸(cross axis)の考え方
  • justify-contentalign-itemsなどの配置プロパティ

これらの基礎知識については、「Flexbox入門 - 柔軟なレイアウトの基本概念を理解する」および「Flexboxの配置プロパティ - justify-content・align-items・align-selfの使い方」で解説しています。

動作確認環境

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

flex-grow・flex-shrink・flex-basisの全体像

3つのプロパティの関係性を理解するために、まず全体像を把握しましょう。

flowchart TB
    subgraph sizing["Flexアイテムのサイズ決定プロセス"]
        direction TB
        basis["flex-basis<br/>基準サイズを決定"]
        check{"余白の状態は?"}
        grow["flex-grow<br/>正の余白を分配"]
        shrink["flex-shrink<br/>負の余白を縮小"]
        final["最終サイズ"]
        
        basis --> check
        check -->|"正の余白(空きスペース)"| grow
        check -->|"負の余白(はみ出し)"| shrink
        grow --> final
        shrink --> final
    end
プロパティ 役割 初期値 値の範囲
flex-grow 正の余白をどの比率で分配するか 0 0以上の数値
flex-shrink 負の余白をどの比率で縮小するか 1 0以上の数値
flex-basis アイテムの基準サイズ auto 長さ・パーセント・auto・content

flex-basis - 基準サイズの設定

flex-basisは、FlexアイテムがFlexコンテナ内に配置される前の初期サイズを指定します。flex-growflex-shrinkによる伸縮計算の基準となる重要なプロパティです。

flex-basisの基本構文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/* キーワード値 */
flex-basis: auto;      /* width/height の値を使用(初期値) */
flex-basis: content;   /* コンテンツに基づいて自動決定 */

/* 長さの値 */
flex-basis: 200px;
flex-basis: 10em;
flex-basis: 50%;

/* 固有サイズキーワード */
flex-basis: max-content;
flex-basis: min-content;
flex-basis: fit-content;

flex-basisとwidthの関係

flex-basiswidth(またはheight)の両方が指定された場合、flex-basisが優先されます。ただし、flex-basis: autoの場合はwidthの値が使用されます。

1
2
3
4
5
6
7
8
9
.item {
  width: 300px;
  flex-basis: 200px; /* 200pxが優先される */
}

.item-auto {
  width: 300px;
  flex-basis: auto; /* 300pxが使用される */
}

autoとcontentの違い

動作
auto width/heightが設定されていればその値、なければcontentと同様
content コンテンツのサイズに基づいて自動決定
1
2
3
4
5
<div class="container">
  <div class="item" style="flex-basis: auto; width: 150px;">Auto (width: 150px)</div>
  <div class="item" style="flex-basis: content;">Content</div>
  <div class="item" style="flex-basis: 200px;">200px</div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
.container {
  display: flex;
  gap: 10px;
  padding: 10px;
  background: #f0f0f0;
}

.item {
  background: #6ab6d8;
  padding: 20px;
  color: white;
}

flex-basisの0と0%の違い

flex-basis: 0flex-basis: 0%は、一見同じように見えますが、特定の状況で異なる動作をします。

説明
0 絶対値として0を指定。アイテムは最小サイズまで縮小可能
0% コンテナの0%を指定。コンテナのサイズが不定の場合はcontentとして扱われる

flex-direction: columnでコンテナに高さが設定されていない場合、0%contentとして解釈されるため、0とは異なる結果になります。

1
2
3
4
/* 推奨: 明示的に 0 を使用する */
.item {
  flex: 1 1 0; /* flex-basis: 0 */
}

flex-grow - 余白の分配

flex-growは、Flexコンテナ内の**正の余白(空きスペース)**を、Flexアイテムにどの比率で分配するかを指定します。

flex-growの基本概念

flowchart LR
    subgraph container["コンテナ 600px"]
        A["A<br/>100px<br/>grow: 1"] 
        B["B<br/>100px<br/>grow: 2"]
        C["C<br/>100px<br/>grow: 1"]
        space["余白<br/>300px"]
    end
    
    subgraph result["分配後"]
        A2["A<br/>175px<br/>(+75px)"]
        B2["B<br/>250px<br/>(+150px)"]
        C2["C<br/>175px<br/>(+75px)"]
    end
    
    container --> result

上の例では、600pxのコンテナに100px×3のアイテムがあり、300pxの余白があります。flex-growの合計は4(1+2+1)なので、余白300pxを4で割った75pxが1単位となります。

  • A: 100px + 75px × 1 = 175px
  • B: 100px + 75px × 2 = 250px
  • C: 100px + 75px × 1 = 175px

flex-growの実装例

1
2
3
4
5
<div class="grow-container">
  <div class="grow-item grow-1">flex-grow: 1</div>
  <div class="grow-item grow-2">flex-grow: 2</div>
  <div class="grow-item grow-1">flex-grow: 1</div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
.grow-container {
  display: flex;
  gap: 10px;
  padding: 10px;
  background: #f0f0f0;
}

.grow-item {
  background: #6ab6d8;
  padding: 20px;
  color: white;
  flex-basis: 100px;
}

.grow-1 {
  flex-grow: 1;
}

.grow-2 {
  flex-grow: 2;
}

flex-grow: 0 の意味

flex-grow: 0(初期値)を指定すると、アイテムは余白を受け取らず、flex-basisで指定したサイズを維持します。

1
2
3
4
5
6
7
8
.fixed-item {
  flex-grow: 0;      /* 伸長しない */
  flex-basis: 200px; /* 常に200pxを維持 */
}

.flexible-item {
  flex-grow: 1;      /* 余った空間を吸収 */
}

この組み合わせは、サイドバーとメインコンテンツのレイアウトに最適です。

1
2
3
4
<div class="layout">
  <aside class="sidebar">固定幅サイドバー</aside>
  <main class="main-content">可変幅メインコンテンツ</main>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
.layout {
  display: flex;
  gap: 20px;
}

.sidebar {
  flex: 0 0 250px; /* 伸縮せず、250px固定 */
}

.main-content {
  flex: 1; /* 残りの空間を全て使用 */
}

flex-shrink - 縮小比率の制御

flex-shrinkは、Flexアイテムの合計サイズがコンテナを超える場合(負の余白)に、各アイテムをどの比率で縮小するかを指定します。

flex-shrinkの基本概念

flex-growとは異なり、flex-shrinkの計算ではflex-basisの値も考慮されます。これは、大きなアイテムほど縮小の影響を受けやすくするためです。

縮小量の計算式は以下のとおりです。

縮小量 = 負の余白 × (アイテムのflex-shrink × flex-basis) / Σ(各アイテムのflex-shrink × flex-basis)

flowchart LR
    subgraph container["コンテナ 500px"]
        A["A<br/>200px<br/>shrink: 1"]
        B["B<br/>200px<br/>shrink: 1"]
        C["C<br/>200px<br/>shrink: 2"]
    end
    
    subgraph overflow["はみ出し: 100px"]
        note["負の余白を<br/>shrink比率で分配"]
    end
    
    subgraph result["縮小後"]
        A2["A: 175px"]
        B2["B: 175px"]
        C2["C: 150px"]
    end
    
    container --> overflow --> result

flex-shrinkの実装例

1
2
3
4
5
<div class="shrink-container">
  <div class="shrink-item shrink-1">shrink: 1</div>
  <div class="shrink-item shrink-1">shrink: 1</div>
  <div class="shrink-item shrink-2">shrink: 2</div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
.shrink-container {
  display: flex;
  width: 500px;
  padding: 10px;
  background: #f0f0f0;
}

.shrink-item {
  background: #6ab6d8;
  padding: 20px;
  color: white;
  flex-basis: 200px;
}

.shrink-1 {
  flex-shrink: 1;
}

.shrink-2 {
  flex-shrink: 2;
}

flex-shrink: 0 で縮小を防ぐ

特定のアイテムが縮小しないようにするには、flex-shrink: 0を指定します。

1
2
3
.no-shrink {
  flex-shrink: 0; /* このアイテムは縮小しない */
}

これは、アイコンやロゴなど、固定サイズを維持したい要素に有効です。

1
2
3
4
<div class="header">
  <img class="logo" src="logo.png" alt="ロゴ">
  <nav class="nav">ナビゲーション</nav>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.header {
  display: flex;
  align-items: center;
  gap: 20px;
}

.logo {
  flex-shrink: 0; /* ロゴは縮小しない */
  width: 100px;
}

.nav {
  flex-shrink: 1; /* 必要に応じて縮小 */
}

flexショートハンド - 推奨される書き方

MDN Web Docsでは、個別プロパティではなくflexショートハンドの使用を推奨しています。ショートハンドを使うことで、3つのプロパティが確実に設定され、意図しない動作を防げます。

flexショートハンドの構文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* flex: flex-grow flex-shrink flex-basis */

/* キーワード値 */
flex: initial;  /* 0 1 auto と同等 */
flex: auto;     /* 1 1 auto と同等 */
flex: none;     /* 0 0 auto と同等 */

/* 値1つ: flex-grow(flex-basisは0になる) */
flex: 1;        /* 1 1 0% と同等 */
flex: 2;        /* 2 1 0% と同等 */

/* 値1つ: flex-basis */
flex: 100px;    /* 1 1 100px と同等 */
flex: 30%;      /* 1 1 30% と同等 */

/* 値2つ: flex-grow flex-shrink */
flex: 1 2;      /* 1 2 0% と同等 */

/* 値2つ: flex-grow flex-basis */
flex: 1 100px;  /* 1 1 100px と同等 */

/* 値3つ: すべて指定 */
flex: 1 1 auto;
flex: 0 0 200px;

よく使うflexの値

展開後 用途
flex: initial 0 1 auto 初期値。縮小のみ可能
flex: auto 1 1 auto 伸縮可能。コンテンツサイズ基準
flex: none 0 0 auto 固定サイズ。伸縮しない
flex: 1 1 1 0% 均等分割。伸縮可能
flex: 0 0 200px そのまま 固定幅200px

キーワード値の使い分け

flowchart TD
    Q1{"アイテムは<br/>伸縮する?"}
    Q2{"コンテンツサイズを<br/>維持する?"}
    Q3{"縮小のみ<br/>許可する?"}
    
    A1["flex: none<br/>0 0 auto"]
    A2["flex: auto<br/>1 1 auto"]
    A3["flex: initial<br/>0 1 auto"]
    A4["flex: 1<br/>1 1 0%"]
    
    Q1 -->|No| A1
    Q1 -->|Yes| Q2
    Q2 -->|Yes| Q3
    Q2 -->|No| A4
    Q3 -->|Yes| A3
    Q3 -->|No| A2

実践例: レスポンシブカードレイアウト

1
2
3
4
5
6
<div class="card-container">
  <div class="card">カード1</div>
  <div class="card">カード2</div>
  <div class="card">カード3</div>
  <div class="card">カード4</div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
.card-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

.card {
  flex: 1 1 300px; /* 最小300px、余白があれば均等に伸長 */
  background: #fff;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

この設定により、カードは最小300pxを維持しつつ、余白があれば均等に伸長します。コンテナが狭くなると自動的に折り返されます。

実践パターン集

パターン1: 固定サイドバー + 可変メイン

1
2
3
4
<div class="layout-sidebar">
  <aside class="sidebar">サイドバー</aside>
  <main class="main">メインコンテンツ</main>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
.layout-sidebar {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  flex: 0 0 280px; /* 固定幅280px */
  background: #2c3e50;
  color: white;
}

.main {
  flex: 1; /* 残りの空間を全て使用 */
  padding: 20px;
}

パターン2: 均等分割ナビゲーション

1
2
3
4
5
6
<nav class="nav-equal">
  <a href="#">ホーム</a>
  <a href="#">サービス</a>
  <a href="#">会社概要</a>
  <a href="#">お問い合わせ</a>
</nav>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
.nav-equal {
  display: flex;
}

.nav-equal a {
  flex: 1;           /* 均等分割 */
  text-align: center;
  padding: 15px;
  text-decoration: none;
  color: #333;
  border-bottom: 2px solid transparent;
}

.nav-equal a:hover {
  border-bottom-color: #3498db;
}

パターン3: メディアオブジェクト

1
2
3
4
5
6
7
<div class="media-object">
  <img class="media-image" src="avatar.jpg" alt="アバター">
  <div class="media-body">
    <h3>ユーザー名</h3>
    <p>コメント本文がここに入ります。長い文章でも適切に折り返されます。</p>
  </div>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
.media-object {
  display: flex;
  gap: 15px;
  align-items: flex-start;
}

.media-image {
  flex: 0 0 60px; /* 固定サイズ、縮小しない */
  width: 60px;
  height: 60px;
  border-radius: 50%;
  object-fit: cover;
}

.media-body {
  flex: 1;        /* 残りの空間を使用 */
  min-width: 0;   /* テキストの折り返しを有効化 */
}
1
2
3
4
5
<div class="page-wrapper">
  <header class="header">ヘッダー</header>
  <main class="content">メインコンテンツ</main>
  <footer class="footer">フッター</footer>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
.page-wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.header {
  flex: 0 0 auto; /* コンテンツに応じたサイズ */
}

.content {
  flex: 1;        /* 残りの空間を全て使用 */
}

.footer {
  flex: 0 0 auto; /* コンテンツに応じたサイズ */
}

よくある間違いと対処法

間違い1: flex-basisとwidthの混同

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* 問題のあるコード */
.item {
  width: 200px;       /* flex-basisで上書きされる */
  flex-basis: 100px;  /* こちらが優先 */
}

/* 推奨: flex-basisのみを使用 */
.item {
  flex: 0 0 100px;
}

間違い2: min-widthを考慮しない

Flexアイテムは既定でmin-width: autoが設定されており、コンテンツの最小サイズ以下には縮小されません。長いテキストがはみ出す場合は、明示的にmin-width: 0を設定します。

1
2
3
4
5
6
7
.item {
  flex: 1;
  min-width: 0;       /* コンテンツより小さく縮小可能に */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

間違い3: flex: 1 の誤解

flex: 1は「均等分割」を意味しますが、これは余白の分配が均等ということであり、アイテムのサイズが均等とは限りません。flex-basis: 0%により、コンテンツサイズに関係なく均等になります。

1
2
3
4
5
6
7
8
9
/* コンテンツサイズに関係なく均等 */
.item {
  flex: 1; /* 1 1 0% に展開 */
}

/* コンテンツサイズを維持しつつ余白を均等分配 */
.item {
  flex: 1 1 auto; /* または flex: auto */
}

ブラウザサポート

flex-growflex-shrinkflex-basis、およびflexショートハンドは、すべての主要なモダンブラウザで完全にサポートされています。

プロパティ Chrome Firefox Safari Edge
flex-grow 29+ 20+ 9+ 12+
flex-shrink 29+ 20+ 9+ 12+
flex-basis 29+ 22+ 9+ 12+
flex 29+ 22+ 9+ 12+

まとめ

本記事では、Flexアイテムのサイズ制御に関する3つのプロパティについて解説しました。

  • flex-basis: アイテムの基準サイズを設定。widthより優先される
  • flex-grow: 正の余白を分配する比率。初期値は0(伸長しない)
  • flex-shrink: 負の余白を縮小する比率。初期値は1(縮小する)
  • flex: 3つのプロパティをまとめて指定するショートハンド。個別指定より推奨

実務では、以下のパターンを覚えておくと便利です。

パターン flexの値 用途
固定サイズ 0 0 200px サイドバー、ロゴ
均等分割 1 ナビゲーション、カード
柔軟な伸縮 1 1 auto メインコンテンツ
縮小のみ 0 1 auto 初期値と同等

これらのプロパティを正しく理解することで、あらゆるデバイスに対応する柔軟で堅牢なレイアウトを実装できるようになります。

参考リンク