Flexboxを使うと、要素の横並び、中央寄せ、均等配置、折り返しを少ないCSSで実装できます。ただし、プロパティを親と子のどちらに書くのか、横方向と縦方向のどちらへ効くのかが分からず、最初につまずきやすい機能でもあります。本記事では、基本から3列カードをスマートフォンで1列にする完成例まで、コピーして確認できるコードで解説します。
Flexboxの基本は親要素にdisplay: flexを書く
Flexboxは、1つの方向に並ぶ要素を柔軟に配置するためのCSSレイアウトです。横一列または縦一列を扱う「一次元」のレイアウトで、行と列を同時に設計するCSS Gridとは役割が異なります。
最初に覚えることは、並べたい要素ではなく、その直接の親要素へdisplay: flexを書くことです。
<div class="flex-container">
<div class="flex-item">カード1</div>
<div class="flex-item">カード2</div>
<div class="flex-item">カード3</div>
</div>
.flex-container {
display: flex;
}
.flex-item {
padding: 20px;
border: 1px solid #ccc;
}
.flex-containerは「Flexコンテナ」、その直下にある3つの.flex-itemは「Flexアイテム」になります。初期状態のflex-directionはrowなので、アイテムは左から右へ並びます。
孫要素まで自動的に横並びになるわけではありません。Flexアイテムになるのは直接の子要素だけです。入れ子の中でもFlexboxを使いたい場合は、その階層の親にもdisplay: flexを指定します。
justify-contentとalign-itemsの違い
Flexboxでは「主軸」と「交差軸」という2つの軸で配置を考えます。初期値のflex-direction: rowでは、主軸が横方向、交差軸が縦方向です。
justify-content:主軸方向の位置や余白を調整align-items:交差軸方向の位置を調整
横方向と縦方向の中央寄せ
.center-box {
display: flex;
justify-content: center;
align-items: center;
min-height: 300px;
}
flex-direction: rowなら、justify-content: centerで横方向、align-items: centerで縦方向の中央へ配置されます。縦中央が変化しない場合は、親要素に余白となる高さがあるか確認してください。高さが内容と同じなら、上下へ移動する空間がありません。
要素間の余白はgapで指定する
.flex-container {
display: flex;
gap: 24px;
}
gapを使うと、最初と最後の要素の外側へ余白を付けず、要素同士の間だけを一定にできます。各アイテムへ個別にmargin-rightを書き、最後の要素だけ打ち消す必要がありません。
よく使うjustify-contentの値
flex-start:開始位置へ寄せるcenter:中央へ寄せるflex-end:終了位置へ寄せるspace-between:両端を揃え、要素間へ均等な余白を入れるspace-around:各要素の両側へ余白を配分するspace-evenly:外側を含むすべての間隔を均等にする
flex-direction: columnへ変更すると主軸が縦になるため、justify-contentは縦方向へ効きます。「justifyは常に横」と暗記せず、主軸の方向で判断するのがポイントです。
折り返しとアイテム幅を指定する
Flexboxは初期状態では折り返しません。要素を複数行にしたい場合は、親にflex-wrap: wrapを指定します。
.card-list {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
子要素の幅はflexショートハンドで調整できます。
.card {
flex: 1 1 280px;
}
3つの値は順番にflex-grow、flex-shrink、flex-basisです。
- 1つ目の
1:空きがあれば拡大する - 2つ目の
1:必要なら縮小する 280px:幅を計算するときの基準サイズ
コンテナが広ければ複数列になり、狭くなって280px前後を保てなくなると次の行へ折り返します。固定幅だけで列数を管理するより、画面幅へ自然に対応しやすい指定です。
均等幅にするだけならflex: 1も使えます。これはアイテムへ空き領域を比例配分する指定です。ただし、長いURLや幅の大きい画像など、内容物の最小幅が原因ではみ出すことがあります。その場合はFlexアイテムにmin-width: 0を加え、画像にはmax-width: 100%を指定して切り分けます。
3列カードをスマートフォンで1列にする完成例
ここでは、PCで3列、タブレットで2列、スマートフォンで1列になるカード一覧を作ります。列数を明確に制御したいので、カード幅をcalc()で計算します。
HTML
<section class="card-list">
<article class="card">
<h3>WordPress</h3>
<p>テーマやプラグインの問題を解決します。</p>
</article>
<article class="card">
<h3>HTML・CSS</h3>
<p>表示崩れやレイアウトを確認します。</p>
</article>
<article class="card">
<h3>JavaScript</h3>
<p>画面操作やエラーの原因を調べます。</p>
</article>
</section>
CSS
* {
box-sizing: border-box;
}
.card-list {
display: flex;
flex-wrap: wrap;
gap: 24px;
max-width: 1000px;
margin: 0 auto;
}
.card {
flex: 0 1 calc((100% - 48px) / 3);
min-width: 0;
padding: 24px;
border: 1px solid #dce7ea;
border-radius: 8px;
background: #fff;
}
@media (max-width: 800px) {
.card {
flex-basis: calc((100% - 24px) / 2);
}
}
@media (max-width: 560px) {
.card {
flex-basis: 100%;
}
}
3列ではカード間の余白が2個あるため、全幅から48pxを引いて3で割ります。2列では余白が1個なので24pxを引いて2で割ります。box-sizing: border-boxを指定すると、paddingとborderを宣言した幅の内側へ含められます。
列数を画面幅に任せたい場合は、前章のflex: 1 1 280pxへ置き換えられます。決められたデザインカンプに合わせるならメディアクエリ、内容に応じて自然に並べるなら基準幅による折り返し、と使い分けると分かりやすいです。
Flexboxが効かないときの確認方法
子要素へdisplay: flexを書いている
横並びにしたい要素の直接の親へ指定します。カード自身にdisplay: flexを書いた場合、横並びになるのはカードの中身です。
flex-wrapがなく、画面からはみ出す
折り返す必要がある一覧にはflex-wrap: wrapを指定します。固定幅、長い文字列、画像の実寸もあわせて確認してください。
justify-contentで変化しない
アイテムがコンテナの幅をすべて使い切っていると、配分できる空き領域がありません。各要素の幅やflex-growを確認します。
縦中央にならない
親要素に高さがあるか、flex-directionがどちらを向いているか確認します。align-itemsが調整するのは主軸と直角の交差軸です。
指定した幅より要素が縮む
Flexアイテムの初期値ではflex-shrink: 1となり、領域が足りないと縮みます。縮めたくない要素にはflex-shrink: 0を検討しますが、スマートフォンで横にはみ出さないかも確認してください。
Chrome DevToolsで配置を確認する
Chrome DevToolsでFlexコンテナを選ぶと、Elementsパネルにflexバッジが表示されます。バッジからオーバーレイを表示すれば、アイテムの領域や間隔を画面上で確認できます。StylesパネルのFlexboxエディターでは、配置の候補をアイコンで試せます。
まとめ
Flexboxは、並べたい要素の親にdisplay: flexを指定するところから始まります。主軸をjustify-content、交差軸をalign-itemsで調整し、複数行にする場合はflex-wrapとgapを組み合わせます。横並びにならないときは、親子関係、空き領域、折り返し、アイテムの最小幅を順番に確認しましょう。