flexbox 完全マスター
こんにちは。エンジニアの左(zuo)です。
みなさんは「フレックスボックス(flexbox)」についてどのような場面で使えると思いますか?同僚のエンジニアに聞いたら「横並び配置で余白を揃えたい時」と返ってきました。
確かに flexbox の半分以上の出番はこれかもしれません。しかしこれだけではもったいない。flexbox にはもっと可能性が秘めています。
前置き
従来のレイアウトは box model の中で display, position や float を駆使するのが一般的でした。しかし中央寄せなど実装しづらい配置がしばし出てきます。
一方 flexbox はどんな配置でも対応でき、しかもレスポンシブであり、全てのブラウザからもサポートされています。現代の CSS においてレイアウトはまず flexbox から考えると言っても過言ではないでしょう。

flexbox とは
一般的には flexible box layout の略で、どんなボックスにも指定できます。
.box {
display: flex;
}
inline 要素にも指定できます。
.box {
display: inline-flex;
}
どちらかが設定された場合、float, clear, vertical-align が無効になります。
基本知識
flexbox の親要素は flex container と呼び、その中の子要素は flex item と呼びます。
さらに軸の概念として、主軸 (main axis) と交差軸 (cross axis) があります。主軸は後述 flex-direction によって指定され、初期値は先頭が左の水平方向です。交差軸は主軸と垂直に交わる軸です。

flex container に指定できるもの
flex-direction
flex-direction は主軸の方向を指定します。
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
row : 初期値。主軸が水平方向で、先頭が左
row-reverse : 主軸が水平方向で、先頭が右
column : 主軸が垂直方向で、先頭が上
column-reverse : 主軸が垂直方向で、先頭が下

flex-wrap
flex-wrap は子要素の flex item が主軸方向の軸(flex-direction が row もしくは row-reverse の場合は行、column もしくは column-reverse の場合は列)からはみ出た場合の折り返しを指定します。
.box {
flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap : 初期値。折り返さない。親要素の寸法が足りない場合に後述の flex-shrink によって子要素が縮小される
wrap : はみ出た場合に折り返す。主軸が水平方向なら下に、垂直方向なら右に新しい軸が配置される
wrap-reverse : はみ出た場合に折り返す。主軸が水平方向なら上に、垂直方向なら左に新しい軸が配置される

(flex-direction: column; の場合)
flex-flow
flex-flow は flex-direction と flex-wrap を一括指定します。初期値は row nowrap です。
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
justify-content
justify-content は主軸方向の子要素の揃え方を指定します。
.box {
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
flex-start: 主軸の先頭揃えで配置する
flex-end : 主軸の末尾揃えで配置する
center: 主軸の中央揃えで配置される
space-between: 主軸方向で、最初と最後の子要素を先頭と末尾に寄せ、他の子要素を等間隔に配置される
space-around: 主軸方向で、全ての子要素の両側の間隔が同じになるように配置される。すなわち最初の子要素の前の余白と最後の子要素の後ろの余白が、隣接の子要素同士の間隔の半分になる
space-evenly: 主軸方向で、最初の子要素の前の余白、最後の子要素の後ろの余白、隣接の子要素同士の間隔が全て同じになるように配置される

align-items
align-items は交差軸方向の子要素の揃え方を指定します。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start: 交差軸の先頭揃えで配置される
flex-end : 交差軸の末尾揃えで配置される
center: 交差軸の中央揃えで配置する
baseline: 交差軸方向の一行目もしくは一列目の文字のベースライン揃えで配置される。交差軸方向の先頭側とベースラインの距離が最も大きい子要素を先頭側の端に配置される
stretch: 初期値。交差軸方向に拡大して配置される

align-content
align-content は交差軸方向の複数の軸の揃え方を指定します。軸が一つしかない場合は無効です。
.box {
align-content: flex-start | flex-end | center | stretch | space-between | space-around;
}
flex-start: 交差軸の先頭揃えで配置される
flex-end : 交差軸の末尾揃えで配置される
center: 交差軸の中央揃えで配置する
stretch: 初期値。交差軸方向に拡大して配置される
space-between: 交差軸方向で、最初と最後の軸を先頭と末尾に寄せ、他の軸を等間隔に配置される
space-around: 交差軸方向で、全ての軸の両側の間隔が同じになるように配置される。すなわち最初の軸の前の余白と最後の軸の後ろの余白が、隣接の軸同士の間隔の半分になる
space-evenly: 交差軸方向で、最初の軸の前の余白、最後の軸の後ろの余白、隣接の軸同士の間隔が全て同じになるように配置される

flex item に指定できるもの
order
order は子要素の順番を指定します。要素は昇順で配置されます。初期値は 0 です。
.item {
order: <integer>;
}

flex-grow
flex-grow は親要素の主軸方向に余白がある場合に子要素の拡張率を指定します。初期値は 0 です。
.item {
flex-grow: <number>;
}

紫の flex container の横幅が 700px の場合、主軸に
700px - 180px - 230px - 170px = 120px
の余白が残ります。以下のように flex-grow を設定すると

左から右にそれぞれ
1 / (1 + 2 + 3) * 120px = 20px
2 / (1 + 2 + 3) * 120px = 40px
3 / (1 + 2 + 3) * 120px = 60px
拡張され、最終的に横幅がそれぞれ
180px + 20px = 200px
230px + 40px = 270px
170px + 60px = 230px
となります。
flex-shrink
flex-shrink は親要素の主軸方向の寸法が足りない場合に子要素の縮小係数を指定します。初期値は 1 です。
.item {
flex-shrink: <number>;
}

紫の flex container の横幅が 500px の場合、主軸方向の flex item の横幅の合計が
150px + 300px + 250px = 700px
と親要素が主軸方向で 700px - 500px = 200px 足りないため flex-shrink が 0 であると flex container からはみ出ます。以下のように 0 以外の数字を設定すると

左から右にそれぞれ
(150px * 2) / (150px * 2 + 300px * 1 + 250px * 4) * 200px = 37.5px
(300px * 1) / (150px * 2 + 300px * 1 + 250px * 4) * 200px = 37.5px
(250px * 4) / (150px * 2 + 300px * 1 + 250px * 4) * 200px = 125px
縮小され、最終的に横幅がそれぞれ
150px - 37.5px = 112.5px
300px - 37.5px = 262.5px
250px - 125px = 125px
となります。
flex-basis
flex-basis は主軸方向の初期(すなわち flex-grow や flex-shrink の適用前)の寸法を指定します。
.item {
flex-basis: <length> | auto;
}
<length> : 主軸方向の寸法
auto : 初期値。要素本来の寸法
他の寸法系のものと同時に指定された場合の優先順位は
max-width/min-width -> flex-basis -> width
flex
flex は flex-grow, flex-shrink と flex-basis を一括指定します。初期値は 0 1 auto です。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
値 1 つを取る場合
-
flex-growで有効なら、flex: <flex-grow> 1 0として展開される -
flex-basisで有効なら、flex: 1 1 <flex-basis>として展開される
値 2 つを取る場合
- 1 つ目は
flex-grow - 2 つ目は
-
flex-shrinkで有効なら、flex: <flex-grow> <flex-shrink> 0として展開される -
flex-basisで有効なら、flex: <flex-grow> 1 <flex-basis>として展開される
-
値 3 つを取る場合
- 1 つ目は
flex-grow - 2 つ目は
flex-shrink - 3 つ目は
flex-basis
どれにも当たらない、もしくは値が有効ではない場合、構文は無効です。
align-self
align-self は子要素自身の揃い方を指定します。親要素の align-items を上書きできます。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
auto 以外の取りうる値は align-items と同じです。初期値は auto で、親要素の align-items の値で設定する意味です。

おわりに
難解な flex-shrink の計算や複雑な flex の仕様を乗り越えてここまで来れたみなさんなら、どんなレイアウトも思い通りに仕上げる力が身についたと思います。素敵な flexbox ライフを!
Discussion