ロールパンのイラスト

flex-wrap: balance で Flexbox の折り返しを均等にする

flex-wrap: wrap では、最後の行に少数のアイテムだけが残り、行ごとのアイテムの量が大きく偏ることがあります。flex-wrap: balance は、通常の折り返しで決まる行数を維持しながら、各行の長さが近くなるように Flex アイテムを振り分けます。この記事では balance 使い方について紹介します。

Flexbox を使ってタグやナビゲーション項目を横に並べるとき、コンテナへ収まらないアイテムを次の行へ送るために flex-wrap: wrap を指定します。しかし、通常の折り返しでは前の行へできるだけ多くのアイテムを詰めるため、最後の行に 1 つだけアイテムが残ることがあります。最後の行に残ったアイテムが flex-grow でコンテナいっぱいに広がると、ほかの行にあるアイテムとの大きさの差も目立ってしまいます。

この偏りを避けるために、コンテナクエリで特定の幅だけマージンを加えたり、JavaScript でコンテナの幅を調整したりする方法が考えられます。しかし、要素の幅が変化するたびに計算を行う必要があり、実装が複雑になります。

.tags {
  container-type: inline-size;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
 
/* この幅では最後のアイテムが 1 つだけ残ることを前提とする */
@container (400px <= width < 460px) {
  .tags li:last-child {
    flex-grow: 0; /* 余った空間を広がるために使わせない */
    margin-inline: auto; /* 残った空間を左右へ均等に配分して中央寄せする */
  }
}

flex-wrap: balance は、通常の折り返しで決まる行数を維持しながら、各行の長さが近くなるように Flex アイテムを振り分ける値です。この記事では、flex-wrap: balance の使い方と、どのように Flex アイテムが各行へ振り分けられるかを紹介します。

Note

2026 年 8 月現在、flex-wrap: balance を利用できるのは Chrome・Edge 150 以降です。Firefox と Safari は対応していません。CSS Flexible Box Layout Module Level 2 は Editor's Draft であり、今後仕様が変更される可能性があります。

flex-wrap: wrap では最後の行が偏る

まずは、通常の flex-wrap: wrap がどのように Flex アイテムを行へ振り分けるか確認しましょう。以下の例では、リストを Flex コンテナにして、各アイテムへ flex: 1 1 80px を指定しています。

<ul class="tags">
  <li>HTML</li>
  <li>CSS</li>
  <li>JavaScript</li>
  <li>Web API</li>
</ul>
.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  max-inline-size: 430px;
  margin: 0;
  padding: 0;
  list-style: none;
}
 
.tags li {
  flex: 1 1 80px;
  padding: 0.75rem 1rem;
  border: 1px solid #6d7fc6;
  border-radius: 0.5rem;
  background: #eef1ff;
  text-align: center;
}

flex の 3 つの値は、順番に flex-growflex-shrinkflex-basis を表します。この例では、各アイテムの基準となる幅を 80px とし、行に余った空間があれば同じ割合で広がるようにしています。

折り返しの判定に使われるのは、flex-basis80px に左右の paddingborder を加えた 114px です。コンテナの幅が 430px の場合、1 行目にアイテムを 3 つ並べると 114px * 3 + 12px * 2 = 366px で収まりますが、4 つ並べると 114px * 4 + 12px * 3 = 492px となりコンテナからはみ出してしまいます。通常の折り返しアルゴリズムは、次のアイテムが収まらなくなるまで現在の行へ追加するため、4 つ目だけが 2 行目へ送られます。その後、各行で flex-grow が計算されるため、2 行目のアイテムは幅いっぱいまで広がってしまいます。

flex-wrap: balance の使い方

flex-wrapbalance を指定すると、折り返した行の長さを均等にできます。

  .tags {
    display: flex;
-   flex-wrap: wrap;  
+   flex-wrap: balance;
    gap: 12px;
  }

これにより、先ほどの 4 つのアイテムは 1 行目と 2 行目にそれぞれ 2 つずつアイテムが配置されるようになります。flex-grow の計算は行ごとに行われるため、2 行のアイテムは同じ程度まで広がります。

balance だけを指定した場合、行を通常の方向へ積み重ねる wrap も指定したものとして扱われます。方向を明示する場合は、以下のように 2 つのキーワードを組み合わせることもできます。

.tags {
  flex-wrap: wrap balance;
}
 
.tags--reverse {
  flex-wrap: balance wrap-reverse;
}

Flex アイテムが各行へ振り分けられる仕組み

通常の wrap は、先頭からアイテムを取り出し、次のアイテムが収まらなくなるまで現在の行へ追加する貪欲法を使います。一度 1 行目へ入ったアイテムを、後から 2 行目へ移して全体を調整することはありません。

一方、balance のアルゴリズム は次の手順で行の区切り位置を選び直します。

  1. 通常の wrap で生成される行数を求める
  2. DOM 順を維持したまま、アイテムをその行数分の連続したグループへ分ける
  3. それぞれの行へ最低 1 つのアイテムを割り当てる
  4. 行に含まれるアイテムの伸縮前の幅(マージンを含む)の合計とコンテナ幅の差を「誤差」とし、全行の誤差の二乗和が最小になる分け方を選ぶ

たとえば、先ほどの 4 アイテムは通常の wrap では 2 行になります。balance も 2 行という数は維持しますが、3 + 1 ではなく 2 + 2 に分けたほうが行ごとの空き幅が近くなるため、3 つ目のアイテムを 2 行目へ移します。

Note

balance は、単純に各行のアイテム数を揃える機能ではありません。各アイテムが伸び縮みする前の幅にマージンを加え、それぞれの行が使う幅ができるだけ近くなるように分けます。そのため、アイテムごとの幅が異なる場合は、行ごとの個数が違う分け方が選ばれることもあります。

行へアイテムを割り当てた後は、行ごとに通常の Flexbox の伸縮処理が行われます。そのため flex-grow を指定した例では、2 + 2 に分かれたそれぞれの行で、アイテムが同じ程度まで広がります。

flex-line-count で最小行数を指定する

通常、balance が使用する行数は、wrap でアイテムを配置した場合と同じです。コンテナにすべてのアイテムが収まるなら、balance を指定しても 1 行のままです。

CSS Flexible Box Layout Module Level 2 では、均等化に使う最小行数を指定する flex-line-count プロパティも定義されています。

.tags {
  display: flex;
  flex-wrap: balance;
  flex-line-count: 5;
}
 
.tags li {
  flex: 1 1 0;
  min-inline-size: 0;
}

flex-basis0 なのでアイテムは通常なら 1 行に収まりますが、この例では最低 5 行へ分けてアイテムを均等化します。指定できる値は 1 以上の整数で、初期値は 1 です。

flex-line-count は最大行数ではない点に注意してください。各アイテムを収めるために 6 行以上が必要なら、flex-line-count: 5 を指定していても必要な数だけ行が作られます。

反対に、指定した値はアイテムの数によって上限が抑えられます。flex-line-count: 5 を指定していてもアイテムが 2 つしかなければ、最小行数は 2 として扱われます。balance はそれぞれの行へ最低 1 つのアイテムを割り当てるため、アイテムの数を超える行が作られることはありません。

なぜ flex-wrap の値として設計されたのか

Flex アイテムを各行へ均等に配置する要望は新しいものではありません。2014 年の CSSWG の議論では、flex-wrap: balance という考え方自体には賛同が得られたものの、Flexbox Level 1 への追加は延期されました。その後、2018 年に CSSWG Issue #3070 として改めて提案されています。

提案の Explainer は、既存の text-wrap: balance から意味を類推しやすく、折り返し方法を制御する flex-wrap の自然な拡張であるとして flex-wrap: balance を提案しました。一方で、折り返すかどうかと、どのようにアイテムを配置するかは別の責務だという考え方もあります。

2025 年 9 月の CSSWG の議論では、均等化を item-pack: balance のような独立したプロパティにする案が検討されました。

まとめ

  • flex-wrap: balance は、通常の wrap で決まる行数を維持しながら、各行のアイテムの伸縮前の合計幅が近くなるように Flex アイテムの改行位置を選び直す
  • flex-line-count は、balance で均等化するときの最小行数を 1 以上の整数で指定する
  • 既存の text-wrap: balance から意味を類推しやすく、折り返し方法を制御する flex-wrap の自然な拡張として設計されたが、item-pack: balance のような独立したプロパティにする案も検討された

参考

記事の理解度チェック

以下の問題に答えて、記事の理解を深めましょう。

通常の `flex-wrap: wrap` と比べた `flex-wrap: balance` の挙動として、記事の説明に合うものはどれですか?

  • アイテムが 1 行に収まるまで、すべてのアイテムの幅を縮小する

    もう一度考えてみましょう

    `balance` はすべてを 1 行へ収める値ではありません。複数行の Flexbox としてアイテムを折り返します。

  • 通常の折り返しで決まる行数を維持し、各行の長さが近くなるように改行位置を選び直す

    正解!

    記事では、通常の `wrap` で行数を求めた後、その行数へアイテムを均等に振り分けると説明しています。

  • 最後の行だけに `justify-content: space-between` を自動で適用する

    もう一度考えてみましょう

    `balance` が変更するのはアイテムを各行へ分ける位置です。`justify-content` の値を変更する機能ではありません。

  • DOM 上のアイテムを幅の短い順へ並べ替えてから折り返す

    もう一度考えてみましょう

    記事では、`balance` は DOM 順を維持した連続するアイテム群へ分けると説明しています。

`flex-line-count: 2` の意味として、記事の説明に合うものはどれですか?

  • 均等化に使用する最小行数を 2 にする

    正解!

    `flex-line-count` は、`balance` でアイテムを均等化するときの最小行数を指定します。

  • アイテムが収まらない場合でも行数を必ず 2 以下に制限する

    もう一度考えてみましょう

    `flex-line-count` は最大行数ではありません。アイテムを収めるために必要なら 3 行以上が作られます。

  • 各行へ必ず 2 個ずつアイテムを配置する

    もう一度考えてみましょう

    指定するのはアイテム数ではなく最小行数です。各行に何個入るかはアイテムのサイズによって決まります。

  • 2 行目から後の Flex アイテムを非表示にする

    もう一度考えてみましょう

    `flex-line-count` は表示を切り詰めるプロパティではなく、Flex アイテムを行へ振り分ける際に使われます。