CSS講座 / Flexboxの基礎:コンテナー・アイテム・二つの軸

Flexboxは、親の直接の子を主軸に沿って並べる一次元のレイアウト方式です。配置を理解するには、並ぶ方向である主軸と、それに直交する交差軸を先に確認します。

親と直接の子を確認する

display: flexを付ける親がFlexコンテナー、その直接の子がFlexアイテムです。divの中にあるspanまで、外側の親のアイテムになるわけではありません。子の中も横並びにしたいときは、その子自身にも別のFlexコンテナーを作れます。

.menu {
  display: flex;
  gap: 12px;
}

Flexboxは一つの軸での配置が基本です。折り返しはできますが、各行の空きはそれぞれに配分され、別の行の列位置まではそろいません。行と列を一緒に制御したい場面はGridの基礎と比較してください。

主軸と交差軸を見分ける

flex-direction: rowではインライン方向が主軸、columnではブロック方向が主軸です。横書きで左から右へ書く条件なら、rowは左から右、columnは上から下へ進みます。row-reverseとcolumn-reverseは、それぞれ主軸の始点と終点を反転します。

横書き左から右の条件で、rowの主軸は横、columnの主軸は縦になる図

図はhorizontal-tbとltrを前提にしています。縦書きや右から左の文章では、rowを常に「左から右」と考えることはできません。justify-contentは主軸、align-itemsは交差軸を扱うため、columnへ切り替えると物理的な方向も変わります。軸の定義はMDNのFlexbox基本概念で確認できます。

初期状態で起きること

通常の初期値はrowとnowrapです。アイテムは主軸の始めに並び、空きがあるからといって自動的にすべて同じ幅に広がるわけではありません。初期のflexは0 1 autoに相当し、拡大には参加せず、必要に応じて縮小します。縮小は内容の最小サイズなどの制約を受けるため、必ず収まるとは限りません。

交差軸では、サイズがautoのアイテムは通常stretchで伸びます。高さが明示された場合や交差軸のautoマージンなど、同じ結果にならない条件もあります。「Flexにすれば高さも幅も全部同じ」ではなく、どの軸のどのサイズを変えたかを確認します。

完全な例で方向と入れ子を比較する

次をflex-direction.htmlとしてUTF-8で保存して開きます。通常のブロック配置、row、column、reverse、入れ子、伸縮を同じページで比較できます。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>flex-direction.html</title>
  <style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.demo { border: 2px dashed #789; padding: 12px; margin-bottom: 20px; }
 .demo > a, .nested > div { padding: 12px; background: #dceefa; }
 .normal > a { display: block; margin-bottom: 8px; }
 .row, .column, .reverse, .nested { display: flex; gap: 12px; }
 .column { flex-direction: column; }
 .reverse { flex-direction: row-reverse; }
 .nested > div { flex: 1; min-width: 0; }
 .nested span { display: block; }
 .initial { display: flex; gap: 12px; border: 2px dashed #789; }
 .initial > div { width: 180px; min-width: 0; padding: 12px; background: #e8f5de; }
  </style>
</head>
<body>
<h1>Same HTML order, different placement</h1>
<h2>Normal block flow</h2><div class="demo normal"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>row</h2><div class="demo row"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>column</h2><div class="demo column"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>row-reverse</h2><div class="demo reverse"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>Direct and nested children</h2><div class="demo nested"><div><span>First line of box A</span><span>Second line of box A</span></div><div>Box B</div></div>
<h2>Initial size and growth</h2><div class="initial"><div>Short description</div><div>Two-line description<br>Second line</div><div>Three-line description<br>Second line<br>Third line</div></div>
<p id="result">This is the link destination. Use the links above to check keyboard navigation order.</p>
</body>
</html>
  1. 通常のブロックが縦に並ぶ様子と、rowの横並びを比べます。columnにあるalign-items: flex-startを一度外すと、交差軸の幅が伸びることを確認できます。元へ戻します。
  2. row-reverseのリンクへTabで移動します。見た目が逆でも、最初・二番目・三番目というHTMLの順番が維持されます。意味のある順序をreverseだけで変えないでください。
  3. 入れ子では外側のAとBだけが横に並びます。内側のdivへdisplay: flexを一時的に追加し、spanの並びも変わることを確認して外します。
  4. 最後のカードの高さと幅を見ます。flex-shrink: 0を追加して狭めると、縮められずはみ出す条件を作れます。確認後は追加を削除します。

並ばないときの確認順序

開発者ツールで、実際の親にdisplay: flexが適用されているか、対象が直接の子かを確認します。次にflex-directionと、子のwidth・height・min-width・marginを見ます。別のルールによる上書きや、想定より一段深い入れ子も原因になります。

横幅が足りない場合は、折り返したいのか、縦に積みたいのかを先に決めます。全体をoverflow: hiddenで隠すと、必要な内容やフォーカス表示も失われます。軸が分かったら整列・折り返し・伸縮で空きの配分を比較できます。