Flexboxの概要と使いどころ

HTML/CSS

Flexboxについて

FlexboxとはCSS3から導入されたレイアウトに関する機能です。Flexboxを利用することで行あるいは列の1次元レイアウトを簡単に実現できます。

Flexboxの適用範囲であるレイアウト全体はFlexコンテナ、Flexboxが適用される要素はFlexアイテムと呼ばれています。1
つまり、Flexコンテナの中にFlexアイテムが並ぶイメージです。

Flexアイテムが並ぶ方向を主軸、主軸に対する垂直方向を交差軸と呼びます。

Flexboxの作り方

  1. Flexboxを適用する要素(Flexアイテム)の集合を作成する
  2. Flexアイテムの集合を親要素(Flexコンテナ)で囲む
  3. Flexコンテナに対して『display: flex』を適用する

具体的なコードは以下の通りです。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>

.container {
  display: flex;
  width: 150px;
  height: 150px;
  border: dotted;
}

.item1 {
  background-color: lightblue;
}

.item2 {
  background-color: greenyellow;
}

.item3 {
  background-color: lightcoral;
}

See the Pen
flexbox-simple
by Toshiharu Nishina (@nishina555)
on CodePen.

Flexアイテムの配置方向の決め方

Flexアイテムの配置方向はflex-directionプロパティで制御します。

flex-directionで指定できる値と意味の対応は以下の通りです。

意味
row 左から右(初期値)
row-reverse 左から右
column 上から下
column-reverse 下から上

たとえばflex-direction: rowの場合、主軸は水平方向、交差軸は垂直方向となります。

Flexアイテムの配置ルールの決め方

justify-contentalign-itemsを利用することでFlexコンテナに存在する各Flexアイテムの配置を一括で制御できます。
justify-contentは主軸に関する、align-itemsは交差軸に関する配置を制御します。

justify-contentで指定できる値と意味の対応は以下の通りです。

意味
flex-start 先頭よせ(初期値)
flex-end 末尾よせ
center 中央よせ
space-between 両端にアイテムを配置し、アイテムを均等に配置
space-around 両端は半分の間隔をあけ、アイテムを均等に配置
space-evenly 両端も同じ間隔をあけ、アイテムを均等に配置

align-itemsで指定できる値と意味の対応は以下の通りです。

意味
stretch コンテナあるいは最長アイテムの高さまで伸張(初期値)
flex-start 先頭よせ
flex-end 末尾よせ
center 中央よせ

以下はjustify-content: space-between; align-items: center;を組み合わせた例です。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>

.container {
  display: flex;
  width: 150px;
  height: 150px;
  border: dotted;
  justify-content: space-between;
  align-items: center;
}

.item1 {
  background-color: lightblue;
}

.item2 {
  background-color: greenyellow;
}

.item3 {
  background-color: lightcoral;
}

See the Pen
flexbox-spece-between-center
by Toshiharu Nishina (@nishina555)
on CodePen.

Flexアイテムの折り返し方法

Flexアイテムの折り返しはflex-wrapプロパティで制御します。
Flexコンテナの領域からFlexアイテムがはみ出る可能性のある場合は、flex-wrapを活用します。

flex-wrapで指定できる値と意味の対応は以下の通りです。

意味
nowrap 折り返さない(初期値)
wrap 折り返す
wrap-reverse 逆順で折り返す

以下はjustify-content: space-between; flex-wrap: wrap;を組み合わせた例です。

<div class="container">
  <div class="item lightblue">item</div>
  <div class="item greenyellow">item</div>
  <div class="item lightcoral">item</div>
  <div class="item lightyellow">item</div>
</div>

.container {
  display: flex;
  width: 150px;
  height: 150px;
  border: dotted;
  flex-wrap: wrap;
  justify-content: space-between;
}

.item {
  width: 60px;
  height: 60px;
}


.lightblue {
  background-color: lightblue;
}

.greenyellow {
  background-color: greenyellow;
}

.lightcoral {
  background-color: lightcoral;
}

.lightyellow {
  background-color: lightyellow;
}

See the Pen
flexbox-spece-between-center-wrap
by Toshiharu Nishina (@nishina555)
on CodePen.

flex-flowプロパティについて

flex-flowflex-directionflex-wrapの一括指定プロパティです。flex-directionflex-wrapの順で指定します。
たとえばflex-flow: row wrap;flex-direction: row; flex-wrap: wrap;と等価です。

各Flexアイテムのサイズを制御する方法

flex-grow, flex-shrink, flex-basisを利用することで各Flexアイテムのサイズを制御できます。
flex-grow, flex-shrink, flex-basisは、Flexコンテナ内に余った配置領域の再分配や、Flexコンテナからはみ出してしまった領域の縮小をします。

flex-basisは伸縮する際の基準値です。0auto、ピクセルなどが指定できます。初期値はautoです。
flex-growには数値が設定できます。数値の比率に応じて余った領域の再分配が行われます。初期値は0です。
flex-shrinkには数値が設定できます。数値の比率に応じてアイテムの縮小が行われます。初期値は1です。

flexプロパティについて

flexflex-grow, flex-shrink, flex-basisの一括指定プロパティです。flex-grow, flex-shrink, flex-basisの順で指定します。
flex: 0 1 auto;flex-grow: 0; flex-shrink: 1; flex-basis: auto;と等価です。

flex-grow, flex-shrink, flex-basisは単体で利用されるケースは少ないです。ですので、Flexアイテム単体のサイズを制御する際はflexを利用するケースがほとんどです。
よく利用される設定はflexの値として定義されています。定義済みの値と意味の対応は以下の通りです。

意味
initial flex: 0 1 auto
auto flex 1 1 auto
none flex: 0 0 auto
1 flex: 1 1 0

特にflex: 1は可変長Flexアイテムを作成する際によく利用されます。

flex-growの具体例

以下のようにFlexコンテナに余白のあるレイアウトがあったとします。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>
.container {
  display: flex;
  width: 200px;
  height: 200px;
  border: dotted;
}

.item1 {
  background-color: lightblue;
  width: 40px;
  height: 40px;
}

.item2 {
  background-color: greenyellow;
  width: 40px;
  height: 40px;
}

.item3 {
  background-color: lightcoral;
  width: 40px;
  height: 40px;
}

See the Pen
flex-grow-before
by Toshiharu Nishina (@nishina555)
on CodePen.

以下では、上記のコードに対してflex-growを適用した結果について紹介します。

すべてのFlexアイテムのflex-growの値が同じ場合

Flexコンテナの余白が均等に各Flexアイテムに振り分けられます。具体例は以下の通りです。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>
.container {
  display: flex;
  width: 200px;
  height: 200px;
  border: dotted;
}

.item1 {
  background-color: lightblue;
  width: 40px;
  height: 40px;
  flex-grow: 1;
}

.item2 {
  background-color: greenyellow;
  width: 40px;
  height: 40px;
  flex-grow: 1;
}

.item3 {
  background-color: lightcoral;
  width: 40px;
  height: 40px;
  flex-grow: 1;
}

See the Pen
flex-grow-after-equal
by Toshiharu Nishina (@nishina555)
on CodePen.

各Flexアイテムで設定されているflex-growの値が異なる場合

flex-growの値の比率に応じてFlexコンテナの余白が振り分けられます。つまり、flex-growの値が大きいFlexアイテムほど幅が広くなります。
具体例は以下の通りです。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>
.container {
  display: flex;
  width: 200px;
  height: 200px;
  border: dotted;
}

.item1 {
  background-color: lightblue;
  width: 40px;
  height: 40px;
  flex-grow: 5;
}

.item2 {
  background-color: greenyellow;
  width: 40px;
  height: 40px;
  flex-grow: 3;
}

.item3 {
  background-color: lightcoral;
  width: 40px;
  height: 40px;
  flex-grow: 1;
}

See the Pen
flex-grow-after-differernt
by Toshiharu Nishina (@nishina555)
on CodePen.

特定のFlexアイテムにのみflex-growが適用されている場合

flex-growのデフォルト値は0です。flex-grow: 0はFlexアイテムが伸張しないことを意味します。
ですので、特定のFlexアイテムにのみflex-growが適用されている場合は当該アイテムにFlexレイアウトの余白がすべて振り分けられます。

具体例は以下の通りです。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>
.container {
  display: flex;
  width: 200px;
  height: 200px;
  border: dotted;
}

.item1 {
  background-color: lightblue;
  width: 40px;
  height: 40px;
  flex-grow: 1;
}

.item2 {
  background-color: greenyellow;
  width: 40px;
  height: 40px;
}

.item3 {
  background-color: lightcoral;
  width: 40px;
  height: 40px;
}

See the Pen
flex-grow-after-only
by Toshiharu Nishina (@nishina555)
on CodePen.

flex-shrinkの具体例

以下のようにFlexアイテムがFlexコンテナからはみ出したレイアウトがあったとします。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>
.container {
  display: flex;
  width: 200px;
  height: 200px;
  border: dotted;
  align-items: flex-start;
}

.item1 {
  background-color: lightblue;
  width: 100px;
  height: 100px;
  flex-shrink: 0; /* デフォルトは1なので明示的に0を指定 */
}

.item2 {
  background-color: greenyellow;
  width: 100px;
  height: 100px;
  flex-shrink: 0; /* デフォルトは1なので明示的に0を指定 */
}

.item3 {
  background-color: lightcoral;
  width: 100px;
  height: 100px;
  flex-shrink: 0; /* デフォルトは1なので明示的に0を指定 */
}

See the Pen
flex-shrink-before
by Toshiharu Nishina (@nishina555)
on CodePen.

以下では、上記のコードに対してflex-shrinkを適用した結果について紹介します。

各Flexアイテムで設定されているflex-shrinkの値が異なる場合

flex-shrinkの値の比率に応じてFlexアイテムが縮小します。つまり、flex-shrinkの値が大きいFlexアイテムほど幅が狭くなります。
具体例は以下の通りです。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>
.container {
  display: flex;
  width: 200px;
  height: 200px;
  border: dotted;
  align-items: flex-start;
}

.item1 {
  background-color: lightblue;
  width: 100px;
  height: 100px;
  flex-shrink: 1; /* デフォルトは1なので指定しなくてもよい */
}

.item2 {
  background-color: greenyellow;
  width: 100px;
  height: 100px;
  flex-shrink: 1; /* デフォルトは1なので指定しなくてもよい */
}

.item3 {
  background-color: lightcoral;
  width: 100px;
  height: 100px;
  flex-shrink: 4;
}

See the Pen
flex-shrink-after-different
by Toshiharu Nishina (@nishina555)
on CodePen.

覚えておくとよいFlexbox内の要素の特性

インライン要素も横幅・高さの指定が可能

display: flex配下において要素はブロックレベル要素のように動作します。2
ですので、インライン要素で定義されたFlexコンテナ・Flexアイテムも横幅や高さの指定ができます。

<span class="container">
  <span class="item">item</span>
</span>

.container {
  display: flex;
  width: 200px;
  height: 200px;
  background: lightgreen;
}

.item {
  width: 150px;
  height: 100px;
  background: lightblue;
}

See the Pen
flexbox-inline
by Toshiharu Nishina (@nishina555)
on CodePen.

要素のデフォルトの幅はコンテンツが収まるサイズ

通常ですと、幅の指定がないブロックレベル要素は親要素の幅と同じになります。

<div class="container">
  <div class="item">item</div>
</div>

.container {
  width: 200px;
  background: lightgreen;
}

.item {
  background: lightblue;
}

See the Pen
Untitled
by Toshiharu Nishina (@nishina555)
on CodePen.

しかしFlexbox配下では、ブロックレベル要素のデフォルトの幅はインライン要素のようにコンテンツが収まるサイズとなります。

<div class="container">
  <div class="item">item</div>
</div>

.container {
  display: flex;
  width: 200px;
  height: 100px;
  background: lightgreen;
}

.item {
  background: lightblue;
}

See the Pen
flexbox-block
by Toshiharu Nishina (@nishina555)
on CodePen.

『text-align: center』でコンテンツの中央寄せはできない

Flexアイテム内のコンテンツを中央寄せする場合、text-align: centerは効きません。

<span class="item">item</span>

.item {
  display: flex;
  width: 200px;
  height: 100px;
  background: lightgreen;
  text-align: center; /* 効かない */
}

See the Pen
flxbox-inline-text-align
by Toshiharu Nishina (@nishina555)
on CodePen.

Flexアイテムのコンテンツの中央寄せしたい場合はjustify-content: centerを利用します。

<span class="item">item</span>

.item {
  display: flex;
  width: 200px;
  height: 100px;
  background: lightgreen;
  justify-content: center; /* 効く */
}

See the Pen
flxbox-inline-justify-content-center
by Toshiharu Nishina (@nishina555)
on CodePen.

参考: autoのmarginによる中央・上下左右寄せはできる

Flexbox配下においてtext-aling: centerによるコンテンツの中央寄せはできませんが、margin: 0 autoによる要素の中央寄せはできます。

<div class="container">
  <div class="item">item</div>
</div>

.container {
  display: flex;
  width: 200px;
  height: 200px;
  background: lightgreen;
}

.item {
  width: 150px;
  height: 100px;
  background: lightblue;
  margin: 0 auto;
}

See the Pen
flexbox-margin-zero-auto
by Toshiharu Nishina (@nishina555)
on CodePen.

同様に上下左右寄せもできます。以下はmargin-bottom: autoを利用した上寄せの例です。

<div class="container">
  <div class="item1">item</div>
  <div class="item2">item</div>
  <div class="item3">item</div>
</div>

.container {
  display: flex;
  width: 200px;
  height: 200px;
  background: lightgreen;
}

.item1 {
  width: 50px;
  background: lightblue;
  border: dotted;
  margin-bottom: auto;
}

.item2 {
  width: 50px;
  background: lightblue;
  border: dotted;
}

.item3 {
  width: 50px;
  background: lightblue;
  border: dotted;
}

See the Pen
flexbox-margin-bottom-auto
by Toshiharu Nishina (@nishina555)
on CodePen.

なお、上記の結果をみてわかる通り、align-items: stretchが適用されていても、align-itemsの軸に対してautoのmarginで要素を寄せると、要素の幅はコンテンツが収まる大きさに縮まります。

Flexboxの利用例

横並びのカードアイテム

ランディングページでよく見る『3つのカード状のアイテムを横に並べる』というレイアウトはFlexboxで実現できます。

具体的なコードは以下の通りです。

<div class="container">
  <div class="item lightblue">item</div>
  <div class="item greenyellow">item</div>
  <div class="item lightcoral">item</div>
</div>
.container {
  display: flex;
  justify-content: space-between;
  border: dotted;
}

.item {
  width: 200px;
  height: 250px;
}

.lightblue {
  background-color: lightblue;
}

.greenyellow {
  background-color: greenyellow;
}

.lightcoral {
  background-color: lightcoral;
}

.lightyellow {
  background-color: lightyellow;
}

See the Pen
flexbox-card-simple
by Toshiharu Nishina (@nishina555)
on CodePen.

上記のコードはjustify-content: space-between;を利用していますが、space-aroundcenterでも実装可能です。
類似コードはCSS Flexboxによる中央寄せ横並びレイアウトの実装3パターン比較でも紹介しています。

ページネーション

ページネーションをはじめとした『固定長のアイテムを指定された間隔で横に並べる』というレイアウトは、たとえばjustify-content: flex-start;margin-rightを組み合わせることで実現できます。
具体例は以下の通りです。

<div class="container">
  <div class="item lightblue">item</div>
  <div class="item greenyellow">item</div>
  <div class="item lightcoral">item</div>
  <div class="item lightyellow">item</div>
</div>
.container {
  display: flex;
  justify-content: flex-start; /*  初期値なので指定しなくてもよい */
}

.item {
  width: 60px;
  height: 60px;
}

.item:not(:last-child){
  margin-right: 10px; /*  最後のアイテムのマージンは不要 */
}

.lightblue {
  background-color: lightblue;
}

.greenyellow {
  background-color: greenyellow;
}

.lightcoral {
  background-color: lightcoral;
}

.lightyellow {
  background-color: lightyellow;
}

See the Pen
flexbox-pagination-simple
by Toshiharu Nishina (@nishina555)
on CodePen.

PCの場合は横並び、スマートフォンの場合は縦並びにする

メディアクエリとflex-directionを利用することで画面幅に応じてアイテムの配置方向を変更できます。
具体例は以下の通りです。

<div class="container">
  <div class="item lightblue">item</div>
  <div class="item greenyellow">item</div>
  <div class="item lightcoral">item</div>
</div>
.container {
  display: flex;
  justify-content: space-between;
  border: dotted;
}

.item {
  width: 200px;
  height: 250px;
}

.lightblue {
  background-color: lightblue;
}

.greenyellow {
  background-color: greenyellow;
}

.lightcoral {
  background-color: lightcoral;
}

.lightyellow {
  background-color: lightyellow;
}

@media screen and (max-width: 599px) {
  /* 600px未満の場合に適用される */
  .container {
    flex-direction: column; /* flexの向きを垂直方向に変更。主軸・交差軸が入れ替わる */
    align-items: center; /* 交差軸を中心揃えにする(= 中央寄せになる) */
    width: 100%; /* 画面の幅に応じて親要素の幅が動的になるようにする */
    }

  .item:not(:last-child) {
    margin-bottom: 10px;
  }
}

See the Pen
flexbox-responsive-simple
by Toshiharu Nishina (@nishina555)
on CodePen.

上記の方法以外でもレイアウトの切り替えは可能です。
レイアウトを切り替える手法の詳細は横並びレイアウトを縦並びに変更するCSS Flexbox実装3パターンまとめをご覧になってください。

2カラムレイアウトを作成する

Webサイトでよく見る『可変長のメインカラムと固定長のサイドバー』というレイアウトはflex: 1を利用することで実現できます。具体例は以下の通りです。

<div class="container">
  <div class="main">main</div>
  <div class="side">side</div>
</div>
.container {
  display: flex;
  border: dotted;
}

.main {
  flex: 1; /* コンテナの余り領域に応じて伸縮する */
  background-color: lightblue;
  min-width: 300px; /* 最低300pxは幅を確保する */
}

.side {
  width: 300px;
  background-color: greenyellow;
}

See the Pen
flexbox-two-columns-simple
by Toshiharu Nishina (@nishina555)
on CodePen.

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!

参考資料