CSSのフレックス・ボックスを理解する

フレックス・ボックス(Flex Box)とは何か

フレックス・ボックスは、CSSで操作可能なレイアウト・モデルの一種です。正確にはフレックス・ボックス・モジュール(Flexible Box Module)と言います。この機能を使用すると、通常のフローでは実現が難しい横並びの配置やレスポンシブデザインの対応が簡単に行えます。

フレックス・ボックスのモデルでは、コンテナとアイテムという二つの関係性を扱います。まずは基本を押さえてから、必要となるプロパティの操作を学んでいきましょう。

以降の内容を読み進める前に、CSSのボックス・モデルについて把握しておくとスムーズに理解できます。ボックス・モデルは、CSSがHTMLの要素をどのように扱うのかを表す基本的な概念です。この仕組みの拡張機能の一種が、フレックス・ボックスなのです。

フレックス・ボックスを開始する

フレックス・ボックスの作成手順は非常に簡単です。フレックス・ボックスのレイアウトを適用したい要素にdisplayプロパティを追加し、その値にflexまたはinline-flexを指定します。

これで下準備が整いました。あとは必要な数だけ子要素を配置し、期待通りのレイアウトに整えていくだけです。フレックス・ボックスの記述内容はそれほど複雑ではありませんが、コンテナやアイテムといった多くの用語が登場するため、言葉の意味を事前に把握しておくことを推奨します。

HTMLとCSSの基本的な構成は以下の通りです。


<div class="container">
	<div class="item">Item 1</div>
	<div class="item">Item 2</div>
	<div class="item">Item 3</div>
	<div class="item">Item 4</div>
	<div class="item">Item 5</div>
</div>

.container {
	display: flex;
	/* コンテナに指定するプロパティ */
}
.item {
	/* アイテムに指定するプロパティ */
}

コンテナとアイテムについて

フレックス・ボックスでは、コンテナとアイテムという二つの主従関係を扱います。コンテナというのはアイテムを包含する親要素、アイテムはコンテナに含まれる子要素です。

コンテナは、displayプロパティの値にflexまたはinline-flexが指定された要素です。この状態の要素は、コンテンツ・ボックスの内部空間にフレックス・ボックスのレイアウトを適用します。これは通常のフローとは別のルールで子要素が配置されることを意味します。

そしてフレックス・コンテナの直下に配置された子要素は、自動的にフレックス・アイテムとして扱われます。フレックス・アイテムにするために、何か特別なCSSを追記する必要はありません。

以下の例を操作してみましょう。displayプロパティの値がblockの場合、子要素は通常のフローに従って配置されます。その値をflexに変更すると、どのように表示されるでしょうか。

フレックス・コンテナに配置された子要素は、displayプロパティの値がflexになった時点で、自動的に横並びになります。これはフレックス・ボックスのレイアウトに関わるプロパティが有効になり、その全てに初期値が適用されるからです。

コンテナに指定できるプロパティとアイテムに指定できるプロパティには、それぞれ別の役目があります。それらを実際に扱う前に、コンテナとアイテムの関係性を理解しておくことが重要です。

主軸と交差軸について

要素にdisplayプロパティのflexを適用すると、ボックスの空間に主軸(main axis)と交差軸(cross axis)が生まれます。既定値では主軸が行方向の並び、交差軸が主軸と垂直に交わる列方向の並びとなります。

主軸の方向は、flex-directionプロパティで定義します。つまり、指定する値を変えると主軸の方向やアイテムの並び方が変わります。既定値ではrowになっているため、省略すると文字と同じ並び方になります。

flex-directionは書字方向と深く関係しています。フレックス・コンテナのプロパティを一切変えなくとも、ドキュメントの書字方向を変えると、主軸の方向やアイテムの並び方が変わります。

書字方向は、directionプロパティやwriting-modeプロパティで定義しますが、英文や日本語を扱っている限り、文章は左から右へ並び、上から下へ積み重なる配置が一般的です。

以下の例は、flex-directionプロパティの値を変更した時に、主軸の方向とアイテムの並び方がどのように変わるのかを示すものです。プルダウン式のセレクトメニューを操作して、実際に確かめてみましょう。

先頭と末尾について

フレックス・ボックスの行には、先頭と末尾という考え方があります。先頭は、その文書の書字方向において文字が先に書かれる方向の端。そして末尾は、文字列が後ろに続いていく方向の端です。

ここで重要なのは、画面に向かって左や右という表現を使わないということです。例えば、directionプロパティの値がltr(Left To Right)の言語圏では、左から右へ向かって文章が書かれるため、フレックス行の左端が先頭、フレックス行の右端が末尾になります。

これがアラビア語などの言語圏で使われるrtl(Right To Left)になると、先頭と末尾の位置が入れ替わり、アイテムの並ぶ順序が逆転します。つまり、flex-directionプロパティの値が同じrowであっても、アイテムの並び方は先頭と末尾を参照するため、左や右という表現では正確性を担保できないのです。

以下の例は、フレックス・ボックスの挙動がdirectionプロパティの値によって変化することを示すものです。コンテナによって制御されるアイテムの並びや寄せ方が変わることを確認して下さい。

ひとつ前の項目で示したサンプルの中にrow-reversecolumn-reverseという値がありますが、これは書字方向を固定したまま、アイテムの並び順を逆にできる機能です。

フレックス・コンテナを理解する

フレックス・ボックスのレイアウトが適用される範囲のことを、フレックス・コンテナと呼びます。これは単に、displayプロパティの値にflexもしくはinline-flexが指定された要素のことを指す場合もあります。

いずれにせよ、フレックス・コンテナは複数の子要素を包含する親要素です。そしてコンテナの直下に配置された子要素のことを、自動的にアイテムとして扱います。

flex-directionプロパティは、フレックス・ボックスのレイアウト全体に関わる主軸の方向とアイテムの並び順を定義します。既定値では、ここにrowが適用されるため、主軸は水平方向、アイテムは文字と同じ順序で並びます。

flex-directionの値を変更した場合の挙動は、主軸と交差軸の項目で解説しています。


.container {
	display: flex;
	flex-direction: column;
}

flex-wrapプロパティは、アイテムの寸法の合計値がコンテナに収まりきらない場合に、それを折り返すのか折り返さないのかを定義します。既定値では、ここにnowrapが適用されるため、アイテムは折り返されずに行を増やしません。

アイテムが折り返されると、コンテナの中に新しい行が追加されます。その行は、各々が独立したフレックス・ボックスとして扱われるため、交差軸に並んだアイテムの寸法は連動しません。


.container {
	display: flex;
	flex-wrap: wrap;
}

flex-flowプロパティは、flex-directionflex-wrapの値を一括で操作するショートハンド・プロパティです。ひとつ目の値で主軸方向とアイテムの並び順を定め、二つ目の値で折り返す方法を定義します。

いずれかの値を省略することも可能です。省略された値には初期値が適用されます。


.container {
	display: flex;
	flex-flow: row wrap;
}

justify-contentプロパティは、フレックス・コンテナの主軸に対してアイテムをどこに寄せるのかを指定します。これは同じフレックス行を共有するアイテムの寄せ方、あるいは余白の分配を定義するものです。

アイテムの中にひとつでも伸長するものがあれば、余白を全て埋めようとするためjustify-contentの効果は無効となります。


.container {
	display: flex;
	justify-content: space-between;
}

align-itemsプロパティは、フレックス・コンテナの交差軸に余白がある場合に、アイテムをどこに寄せるのかを指定します。この機能は、全てのアイテムに対してalign-selfを指定する場合と同じ効果をもたらします。


.container {
	display: flex;
	align-items: center;
}

align-contentは、アイテムが複数行に渡って並ぶ場合の揃え位置を指定します。この機能はコンテナの交差軸の寸法に余裕があり、アイテムの並びが複数行に渡っている場合にのみ有効です。そのため、flex-wrapの値がnowrapである場合は効果が現れません。

既定値ではstretchが適用されているため、アイテムの交差軸の寸法が自動的に伸縮します。startendの位置指定は、フレックス・ボックスの先頭と末尾の概念に対応しています。


.container {
	display: flex;
	flex-wrap: wrap;
	align-content: start;
}

gapプロパティは、隣接するアイテム同士の間隔を指定します。このプロパティは、列方向の隙間を操作するcolumn-gapプロパティと、行方向の隙間を操作するrow-gapプロパティのショートハンドです。

ひとつ目の値がrow-gap、二つ目の値がcolumn-gapを表しますが、二つ目の値を省略すると両方が同じ寸法であるとみなされます。

この機能の特徴は、アイテム同士が隣接する空間のみに作用する点です。基本的にはコンテナの内側に向いている辺にしか隙間を与えません。アイテムの辺とコンテナの辺が隣接する外側の隙間には影響を与えないということです。

これまで、アイテム同士の隙間をmarginで操作していた場合、レスポンシブデザインなどでレイアウトが変化した時に、余白が過剰になるケースがありました。この問題は、多くの場合gapを使うことで解消できます。


.container {
	display: flex;
	gap: 1rem;
}

フレックス・アイテムを理解する

フレックス・ボックスのレイアウトが適用される範囲に属している子要素のことを、フレックス・アイテムと呼びます。アイテムであるかどうかを定義するのは、親要素のdisplayプロパティであるため、アイテム自身に何か特別なプロパティを付加する必要はありません。

アイテム自身に指定するプロパティは、同じフレックス・ボックスに属するアイテム同士の相対的な関係の中で、自身がどのように振る舞うのかを定義するものです。個別の指定が必要ない場合は、コンテナ側で制御できるため、機能的な役割りを整理しておくと理解しやすいでしょう。

flex-growプロパティは、アイテムが主軸方向に伸長する倍率を定めます。この値は、同じフレックス・ボックスの空間を共有しているアイテム同士の相関関係を表します。

flex-growの値は、整数または小数点を含む数値で示します。これが0の場合、アイテムはコンテナに余白があっても伸長しません。逆に1やそれ以上の数値が指定してあってもコンテナの行に余白がない場合は機能しません。

この機能によって計算されるアイテムの寸法は固定値ではないため、例えflex-growの値が同じであっても、別のフレックス・ボックスに属するアイテムの寸法とは一致しません。


.item {
	flex-grow: 1;
}

flex-shrinkプロパティは、アイテムが主軸方向に収縮する倍率を定めます。この値は、同じフレックス・ボックスの空間を共有しているアイテム同士の相関関係を表します。

flex-shrinkの値は、整数または小数点を含む数値で示します。これが0の場合、アイテムは基準となる寸法を尊重して収縮しません。また、コンテナの主軸方向に十分な余白がある場合も、収縮する必要がないので効果が現れません。

基本的な動作は、flex-shrinkの値が大きくなるほど収縮の倍率が増えます。例えば、同じ条件のアイテムに24を指定した場合は、4の方が多く寸法を減少させます。


.item {
	flex-shrink: 1;
}

flex-basisプロパティは、アイテムの主軸方向に対する寸法の基準です。ここで指定された基準は、flex-growflex-shrinkを計算する祭に利用されます。

flex-basisの値は、あくまでアイテムの理想的な寸法です。実際に画面に表示される大きさは、コンテナのサイズ、アイテムの数、他のプロパティの値などによって変動し、最終的にはできるだけ指定された寸法に近い形で表示しようとします。

アイテムはflex-basiswidthの両方が指定されていた場合、flex-basisを優先しますが、その値がautoであった場合はwidthの値も参考にします。


.item {
	flex-basis: 100px;
}

flexプロパティは、flex-growflex-shrinkflex-basisの値をまとめて指定するショートハンド・プロパティです。全ての値を並べて記述する方法と、キーワードによる一括操作が行えます。

flexを使用する場合は、値の順番に気を配る必要があります。基本的には、先に示したリンクの順番通りですが、値を省略した場合に適用される初期値も理解しておく必要があります。

フレックス・アイテムを伸縮させるために一番手軽な値としてflex: 1;が使われますが、この値が何を意味しているのか、事前にflexの解説を読んで把握しておきましょう。


.item {
	flex: 1 0 100px;
}

align-selfプロパティは、コンテナの交差軸に余白がある場合に、アイテムをどこに寄せるのかを個別で指定します。これはalign-itemプロパティと同じ機能ですが、align-selfはアイテム自身に付加して、個別指定を行う場合に有効です。

コンテナ側にalign-itemが指定されている場合は、これを上書きします。また、コンテナの交差軸に十分な余白がなければ効果が現れません。


.item {
	align-self: center;
}

orderプロパティは、コンテナの中に配置されたアイテムの並び順を指定します。この機能は、HTMLのソースコード上で記述された順序とは関係なく、コンテンツの配置を視覚的に変更したい場合に有効です。

orderを使用する場合は、並び順を変えないアイテムにも同様にプロパティを付加しておいた方が安全です。orderの初期値は0であるため、このプロパティを指定したプロパティの前に割り込むためです。

以下の例は、5つ並べたアイテムの先頭に指定したorderの値を変えていった場合の挙動です。HTMLのソースコードを変えなくとも、このように画面上の位置を動かすことができます。


.item {
	order: 3;
}

まとめ

以上でフレックス・ボックスの解説は終わりです。上記で示した内容を理解すれば、フレックス・ボックスを思い通りに使いこなせるようになります。まずは個別のプロパティを暗記するよりも先に、コンテナとアイテムの関係性、主軸と交差軸の概念、先頭と末尾などの用語を把握しましょう。

プロパティを指定したのに効かない、期待した通りに画面に表示されないといった問題の多くは、そこで使われている言葉を理解することで解決します。分からなくなったら、もう一度このページへ戻って来て内容を確認してみましょう。

これ以降の作業は、実際に手を動かして色々なパターンのフレックス・ボックスを作成してみることです。各プロパティのページにサンプルを掲載しているので参考にして下さい。

CSSリファレンス一覧