display: flex の役割
親に display: flex を指定すると、直接の子要素が横一列に並び、同じ高さに引き伸ばされます。要素を横に並べるための float、inline-block、ほとんどの位置指定のテクニックが、この 1 つの宣言で置き換わります。
1 つ目のボックスでは、それぞれの div が 1 行を占めます。2 つ目では 3 つのアイテムが 1 行に並び、それぞれ内容の幅しかなく、One と Three は Two の高さまで引き伸ばされます。変えたのは親だけです。display: flex は コンテナ に書き、アイテムには書きません。
flexbox プレイグラウンド
値を選んで、アイテムが動くのを見てください。ボックスの下のコード行が見えている状態の CSS で、その下のリストは、ブラウザが実際に各アイテムを置いた位置を getBoundingClientRect() で測ったものです。
試してみること:
justify-content: space-between: アイテム 1 は x 0 に置かれ、アイテム 3 は反対側の端に接します。align-items: center: 3 つのアイテムはそれぞれの高さを保ち、中心がそろいます。初期値のstretchでは、アイテム 1 には自分の高さがないので、コンテナの 170px いっぱいに広がります。flex-direction: column: 今度はjustify-contentがアイテムを 縦方向 に、align-itemsが横方向に動かします。2 つのプロパティは画面ではなく軸に従います。
主軸と交差軸
flex コンテナにはすべて 2 つの軸があります。主軸 はアイテムが並ぶ方向で、flex-direction で決まります。交差軸 はそれと直角に交わります。
flex-direction | 主軸 | 交差軸 | justify-content の動かす方向 | align-items の動かす方向 |
|---|---|---|---|---|
row (初期値) | 横、読む順 | 縦 | 横 | 縦 |
row-reverse | 横、逆順 | 縦 | 横 | 縦 |
column | 縦、上から下 | 横 | 縦 | 横 |
column-reverse | 縦、下から上 | 横 | 縦 | 横 |
右から左のページ (dir="rtl") では、主軸が書字方向に従うので、row は右端から始まります。
コンテナのプロパティ
これらは display: flex の要素に書きます:
| プロパティ | 役割 | 初期値 |
|---|---|---|
flex-direction | 横か縦か、どちら向きか | row |
flex-wrap | 場所が足りないときにアイテムを次の行に送るか | nowrap |
flex-flow | flex-direction と flex-wrap のショートハンド | row nowrap |
justify-content | 主軸に沿った配置と間隔 | normal (flex-start として動作) |
align-items | 交差軸に沿ったアイテムの配置 | normal (stretch として動作) |
align-content | アイテムが折り返したときの行と行の間隔 | normal |
gap | アイテムの間のすき間 (row-gap、column-gap) | 0 |
justify-content と align-items のすべての値は、専用のページで解説しています: justify-content と align-items。折り返しと方向は flex-wrap のページ にあります。
アイテムのプロパティ: flex-grow、flex-shrink、flex-basis
これらは子要素に書き、コンテナの幅の分け方を決めます:
flex-basis: 空きスペースを分ける前の、アイテムの出発点のサイズ (autoは「自分の width か内容を使う」という意味)。flex-grow: 残った スペースを何単位分もらうか。0なら伸びません。flex-shrink: スペースが足りないときにどれだけ譲るか。0なら縮みません。
flex のショートハンドで 3 つをまとめて指定します:
| 書き方 | 意味 | 動き |
|---|---|---|
flex: initial (初期値) | 0 1 auto | 内容のサイズ。縮むことはあるが伸びない |
flex: 1 | 1 1 0% | 0 から始まり、スペースを均等に分ける |
flex: auto | 1 1 auto | 内容のサイズに、残りのスペースの分け前を足す |
flex: none | 0 0 auto | 内容か width ちょうど。伸びも縮みもしない |
flex: 2 | 2 1 0% | flex: 1 のアイテムの 2 倍の分け前 |
どの行も padding の内側が幅 480px で、8px のすき間 2 つを引くと、アイテムに使えるのは 464px です。表示された幅で分け方がわかります。1 行目はそれぞれ約 155px、2 行目は 116 + 232 + 116 (flex: 2 のアイテムは隣のそれぞれの 2 倍の分け前)、3 行目は 100 + 372 で、flex: none のアイテムは幅を保ち、もう一方が残りをすべて取ります。
flexbox で作る実際のレイアウト
最初にロゴ、最後にリンクを置くヘッダーは、一番よくある flex のレイアウトです。1 つのアイテムに margin-inline-start: auto を付けると、その前の空きスペースをすべて使い、そのアイテムと後に続くものを最後まで押し出します:
align-items: center で大きいロゴの文字とリンクの高さがそろい、gap を使えば最後のリンクの margin を打ち消す必要もなく、リンクの間隔が空きます。
もう 1 つの日常的なパターンがメディアの行です。固定サイズのアイコンと、残りの幅を使って自分の列の中で折り返す文章です。
flex: none がそれを保証します。flex アイテムは初期状態で縮むので、円から flex: none を消し、文章からも flex: 1 を消すと、段落が円を幅約 23px まで押しつぶし、楕円になります。1 つのものをボックスの中央に置くなら、flexbox では 2 行です (justify-content: center; align-items: center)。ほかの方法との比較は div の中央寄せのページ にあります。
order とアクセシビリティ
order プロパティと -reverse の方向は、アイテムが 表示される 位置を変えるだけで、HTML の中の位置は変えません。スクリーンリーダーと Tab キーは HTML の順番に従うので、キーボードで操作する人は、画面の最初のリンクから最後のリンクに飛ぶことがあります。これらは見た目のためだけに使い、順番に意味があるときは HTML を変えましょう。
flexbox か grid か
flexbox は一度に 1 方向で動きます。行の中のアイテムは内容に合わせてサイズが決まり、(折り返しで) 2 行目ができても 1 行目とそろいません。grid は 2 方向で動きます。列と行を定義すると、アイテムがそこにはまります。ナビゲーションバー、ツールバー、フォームの行は flexbox、ギャラリーやサイドバー付きのページは grid です。
よくある間違い
- 親ではなくアイテムに
display: flexを付ける。display: flexはコンテナに付け、その子要素がアイテムになります。 - 高さがないのに
align-itemsでアイテムが縦に動くと思う。 コンテナの高さが一番高いアイテムと同じなら、動く余地がありません。コンテナに高さを与えましょう。そうでなければ、正しく動いていてもすることがないだけです。 - 文字が縮まずにはみ出す。 flex アイテムは
min-width: autoです。縮ませたいアイテムにmin-width: 0を追加しましょう。 flex: 1なのに幅が違うのはなぜ?flex: 1のアイテムはスペースを均等に分けますが、内容が収まらないアイテム (長い URL、画像) はそれより小さくは縮みません。これもmin-width: 0で直ります。- アイテムの間に margin を付ける。 コンテナに
gapを使いましょう。gap はアイテムの間にだけ入ります。 - 不要に flex を入れ子にする。 flex アイテムになるのは直接の子要素だけです。孫要素は、その親も
display: flexでない限り、通常のレイアウトに従います。
よくある質問
display: flex は何をしますか?
要素を flex コンテナにします。直接の子要素は flex アイテムになり、初期状態では横に並んで同じ高さに引き伸ばされます。justify-content、align-items、gap などのプロパティで、スペースの分け方を制御します。
flex: 1 はどういう意味ですか?
flex: 1 は flex: 1 1 0% の省略形です。アイテムは伸びることができ (flex-grow: 1)、縮むことができ (flex-shrink: 1)、サイズ 0 から始まります (flex-basis: 0%)。すべて flex: 1 のアイテムは空きスペースを均等に分けるので、内容が収まらない場合を除いて同じ幅になります。
justify-content と align-items の違いは何ですか?
justify-content は主軸 (横並びなら横方向) に沿ってアイテムを配置し、align-items は交差軸 (横並びなら縦方向) に沿って配置します。flex-direction: column では 2 つの軸が入れ替わり、justify-content が縦方向になります。
flexbox と grid のどちらを使うべきですか?
アイテムが内容に合わせてサイズが決まる 1 行か 1 列には flexbox を使います。ナビゲーションバー、ボタンのグループ、入力欄の横のラベルなどです。カードのグリッドやページのレイアウトのように、行と列をそろえたいときは grid を使います。
flex アイテムがコンテナからはみ出すのはなぜですか?
flex アイテムは初期状態で min-width: auto なので、一番長い単語や一番幅の広い子要素より小さくは縮みません。アイテムに min-width: 0 (または overflow: hidden) を指定すると縮めるようになり、たとえば text-overflow: ellipsis が効くようになります。
flexbox は span のようなインライン要素にも使えますか?
使えます。display: flex の要素はどれでも flex コンテナになり、その子要素は自分の display の値に関係なく flex アイテムになります。そのため <span> の子要素もインラインではなくなり、block のように幅、高さ、margin が効きます。