display:flex;で柔軟な横並びを実現

display:の値にはblockinline、inline-blockなどがありますが、これらは子要素に設定した上で、子要素が自分自身の幅だけをみて勝手に並ぶ方式でした。

けれども、横並びのinlineでは高さがそろわなかったり、inline-blockでは隙間が生じたり、あるいはfloatを使用しても高さが消えるなど様々な問題がありました。

  • inline → 高さが揃わない
  • inline-block → 隙間が生じる
  • float → 高さが消えたり、クリアが必要

そのため、親要素が子要素の並び方を一括で管理する方式にしたのが、display:flex;のFlex layoutモデルです。単にFlexbox、あるいはFlex layoutなどとも呼ばれています。このモデルでは、親要素にdisplay:flex;を設定することで、子要素の横並びを一括で管理して配置することができます。

また、W3Cの公式名称は「CSS Flexible Box Layout Module」となっていますが、「FlexibleなBoxのLayout」の意味のため、子要素のボックスが余った余白を埋めるように伸縮するという特徴もあります。

display:flex;は親要素と子要素の組み合わせが重要

Flexbox は、親要素に display:flex; を指定することで、その子要素が並び方や揃え方の対象になるため、「親要素 + 子要素」の組み合わせが重要になります。

  • 親要素:配置の基本ルールを決める(方向、間隔、揃え方、折り返しなど)
  • 子要素:必要なら個別に設定(順番、伸縮の有無、個別の揃えなど)

Flexboxのイメージ

例えば、以下のようなリストタグがあったとします。

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

従来のinline-blockでの横並び

このリストタグを従来のdisplay:inline-blockで横並びにする場合、子要素のliにプロパティを設定して以下のようになります。

li {
  display: inline-block;
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
  • 1
  • 2
  • 3
  • 4
  • 5

flexでの横並び

一方、display:flex;で横並びにするには、親要素のulに設定して以下のようになります。

ul {
  display: flex;
  gap:10px;
  list-style:none;
}

li {
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
  • 1
  • 2
  • 3
  • 4
  • 5

どちらも同じように横並びになりますが、display: flex;の場合は親要素がルールを一括で管理している点で違いがあります。

また、上記リストタグの場合は<ul>が親要素、<li>が子要素になりますが、<div>の場合には以下のようになります。

<div class="example">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
</div>
.example {
  display: flex;
  gap:10px;
}

.example div {
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
1
2
3
4
5

子要素の種類は問わず、<span>などが混ざっていても問題ありません。

<div class="example">
  <div>1</div>
  <span>2</span>
  <div>3</div>
  <span>4</span>
  <div>5</div>
</div>
1
2
3
4
5

一方、子要素がテキストのみの場合、flexの対象となるのはタグのため、display:flex;は実質的に効きません。

<div class="example">
12345
</div>
12345

そのため、テキストにflexを効かせる場合には、<span>や<div>で囲んでおくことをおすすめします。

gap:縦 横;を指定してボックス間の間隔を調整

display:flex;で横並びにした際、子要素のボックス間の間隔を調整したい場合にはgapを使用します。このgapはFlexbox専用のプロパティではなく、gridなども含めたボックス間の間隔を指定する際の共通プロパティとなっています。

このgapを記載する際、paddingやmarginのような4つの値ではなく、「縦方向」と「横方向」の2つの値を指定します。

gap: 縦 横;

値を1つだけ指定した場合、縦と横は同じ値のショートハンドとなります。

例えば、「gap: 10px 10px;」と「gap: 10px;」は同じ意味になります。

ただ、上下と左右に10pxの間隔があくわけではなく、子要素同士の間隔で10pxという意味になります。

.example {
  display: flex;
  gap:10px;
  border:2px solid #ccc;
}

.example div {
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
1
2
3
4
5

上記の場合は横方向のみですが、折り返した場合など、縦方向にも10pxが空きます。

1
2
3
4
5

なぜmarginのような4つの値ではないかといいますと、gapはgridなども含めた共通プロパティのため、行列の2軸が基本となり、親要素が子要素のボックス全体を一括して管理するためのものだからです。

そのため、上下右左も含めて子要素の余白の間隔を個別に調整する際には、子要素にmarginを指定して調整します。

その際、marginの値はgapに上乗せされて調整されることになります。

例えば、以下のようにあったとします。

.example {
  display:flex;
  gap:16px;
}
.example div {
  margin-right:8px;
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
1
2
3
4
5

この場合、gapで16px、margin-rightで8pxのため、合計で右側は24pxの間隔となります。

flex-directionで縦方向、横方向の向きを指定

display:flex;のデフォルトでは横並びとなりますが、縦方向に並べる場合にはflex-direction(flexの方向)で以下のように指定します。

.example {
  display: flex;
  flex-direction:column;
  gap:10px;
}

.example div {
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
1
2
3
4
5

flex-direction: row; はデフォルトのため、あえて書くケースは少ないです。そのため、flex-directionを使用するとすれば、ほぼflex-direction: column;となるため、これだけを覚えておくとよいでしょう。

  • flex-direction: row; 横方向(デフォルト)
  • flex-direction: column; 縦方向

そのほか、row-reverseやcolumn-reverseもありますが、こちらもあまり使いません。

  • flex-direction: row-reverse; 横並び(右→左)
  • flex-direction: column-reverse; 縦並び(下→上)

flex-directionの値は上記の4種類となりますが、使用する頻度はそれほど高くはないと思います。

align-items:center;は高さの中央揃えで使用頻度が高い

例えば、以下のような高さ80pxの要素があったとします。

<div class="example">
12345
</div>
.example {
  height:80px;
  background: #fbecdf;
}
12345

このテキストを高さの中央に配置する際、以前までは「height」と「line-height」を同じ値に合わせるなどして設定する必要がありました。

.example {
  height: 80px;
  line-height: 80px;
  background: #fbecdf;
}
12345

ただ、この方法は単純なテキストであれば中央に見えますが、複数行のテキストやアイコン+テキストのような複合要素ではうまく中央にならず、扱いづらい面がありました。

あるいは、heightを指定せず、「上下のpadding+文字の高さ」を計算して見た目だけ中央に寄せるといった方法もあります。ただ、複数行になるとズレますし、親の高さが決まっていない状態では本質的な意味で高さの中央揃えとはなりません。

.example {
  padding: 27px 0;
  background: #fbecdf;
}
12345

一方、align-items:center;を使用することにより、数値を指定する必要もなく、一発で高さの中央に配置することができます。そのため、この高さの中央揃えの用途でのみ、ワンポイント的に単独で使用されることも多く、使用頻度の高いプロパティとなっています。

.example {
  display: flex;
  align-items: center;
  height:80px;
  background: #fbecdf;
}
12345

ちなみに、要素の中にあるテキストもflexの仕組み上は子要素として扱われるため、必ずしも<span>などのタグで囲う必要はありません。ただし、テキストはインライン要素として扱われるため、幅や高さの計算が曖昧になりやすく、レイアウトが不安定になることがあります。

そのため、できるだけ、テキストを<span>や<div>で囲んでおいた方が安定しやすくなります。

上記のように、align-items:center;は「高さの中央揃え」を簡単に実現できるため、flexの中でも使用されることが多いプロパティとなっています。

その他、display:flex;で使用するalign-itemsの値には以下の種類があります。

  • stretch(高さを伸ばす、デフォルト)
  • flex-start(上寄せ)
  • flex-end(下寄せ)
  • center(高さ方向の中央揃え)
  • baseline(テキストのベースライン揃え)

他にも種類はあるものの、Flexboxで使っても意味がない値があるため、display:flex;で使用する際は主に上記になります。

justify-contentで横方向の揃え方を指定

align-items が高さ(縦方向)の中央揃えを指定するのに対し、justify-contentは横方向の揃え方を指定します。

  • 縦方向=align-items
  • 横方向=justify-content

例えば、以下のようなナビゲーションがあったとします。

<div class="example">
  <div>HOME</div>
  <div>運営者</div>
  <div>連絡先</div>
</div>

justify-content: flex-start;(デフォルト)

このままdisplay:flex;を指定すると、何も指定しないデフォルトではjustify-content: flex-start;(左寄せ)のため、子要素は左寄せで並びます。

.example {
  display: flex;
}

justify-content: flex-end;(右寄せ)

justify-content: flex-end;は右寄せのため、子要素は右寄せで並びます。

.example {
  display: flex;
  justify-content: flex-end;
}

justify-content: center;(中央揃え)

テキストを子要素内で左寄せにしたまま、子要素自体を中央に揃える場合はjustify-content: center;を指定します。

.example {
  display: flex;
  justify-content: center;
}

text-align:center;との違い

justify-content: center;とtext-align:center;との違いは、「text-align は子要素内のテキストを中央揃えするプロパティであり、子要素自体の配置には影響しない」という点です。

そのため、子要素そのものを横方向に中央揃えしたい場合にはtext-alignではなく、上記のjustify-content: center;を使用する必要があります。

一方、子要素内のテキストを中央に揃えたい場合には、子要素にtext-align:center;を指定します。

.example div {
  text-align:center;
}

justify-content: space-between;(子要素間のスペースのみ均等)

さらに、justify-content: space-between;を指定した場合、子要素を左右端にくっつけた状態にて、子要素間の余白が均等になります。

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

justify-content: space-around;(左右には半分のスペース)

justify-content: space-around;を指定した場合、子要素が左右の端にくっつくのではなく、子要素間の半分のスペースを確保した上で、子要素間のスペースが均等になります。

.example {
  display: flex;
  justify-content: space-around;
}

justify-content: space-evenly;(左右も含めて均等)

さらに、justify-content: space-evenly;を指定した場合、全てのスペース間が均等になります。

.example {
  display: flex;
  justify-content: space-evenly;
}

flex-direction:column;との関係

一方、上記のflex-direction:column;を指定すると縦の方向に並びます。この場合、交差する軸が逆になるため、justify-content: center;ではなく、align-items: center; を使用することで中央揃えにすることができます。

上記のように、中央揃えでも「text-align:center;」、「justify-content: center;」、「align-items: center;」、「flex-direction: column;」で違いが出て来るので注意しましょう。

flex-wrap: wrap;で折り返しを指定

display:flex;で子要素を横並びにする際、折り返しの方法を指定するのがflex-wrapです。

このflex-wrapの値には、nowrap、wrap、wrap-reverseの3種類がありますが、nowrapは横スクロールなどの特殊用途ですし、wrap-reverseもほぼ使われません。そのため、実質的にはflex-wrap: wrap;で使用するケースがほとんどかと思います。

flex-wrap: nowrap;(デフォルト)

何も指定しないデフォルトではflex-wrap: nowrap;ですが、この場合は折り返しなしで横に伸び続けることになります。

.example {
  display: flex;
  flex-wrap: nowrap;
}

この場合、親要素も突き抜けてしまうため、以下のwrapで折り返す設定にするか、もしくはoverflow-x: auto;でスクロール設定にすることをおすすめします。

.example {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
}
1
2
3
4
5
6
7
8
9

flex-wrap: wrap;(折り返し)

子要素の数が多く、親要素を突き抜けてしまう場合、上記のスクロール設定にするか、もしくはflex-wrap: wrap;で折り返しの設定をすることをおすすめします。

.example {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  width: 200px;
  border: 2px solid #ccc;
  padding: 10px;
}

.example div {
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
1
2
3
4
5

wrapを指定することで、親要素を突き抜けずに、次の行へ移動して複数行で表示されます。

flex-wrap: wrap-reverse;(上方向への折り返し)

そのほか、wrap-reverseもありますが、こちらは下ではなく、上方向へ積み上げる折り返し設定となり、特殊なため、使用するケースはほぼないと思います。

flex-wrap: wrap;とalign-contentの関係

align-items は「単一行の縦揃え」を指定するプロパティであるのに対し、align-contentは「複数行の縦揃え」という違いがあります。そのため、align-contentはflex-wrap: wrap;との組み合わせで使用されることもあります。

.example {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
}

ただ、親要素に高さが設定されていないケースも多く、余白がないと上下や中央に動きようがないため、使用頻度でいえば、それほど高くはないかもしれません。

display:flex;でテンプレートのレイアウトを構成する方法

display:flex;は、テンプレートのレイアウトを構成する際にも便利です。

例えば、以下のような3カラムがあったとします。

記事
左カラム
右カラム

この場合、検索エンジン対策上は、記事のarticleをHTMLソースの一番最初に記載するのが最適です。

<main>
  <article>記事</article>
  <div class="left">左カラム</div>
  <div class="right">右カラム</div>
</main>

けれども、そのままの状態ですと、レイアウト上では記事が一番左に配置されてしまうため、中央に配置するにはfloatを設定して調整する必要がありました。

その点、親要素にdisplay:flex;を設定した上で、子要素にorderで順番を指定することにより、簡単に3カラムを配置することができます。

main {
  display:flex;
  gap:10px;
  width:400px;
}
article {
  order: 2;
  flex:1;
}
.left {
  order: 1;
  width:50px;
}
,right {
  order: 3;
  width:100px;
}
記事
(自動で伸縮)
左カラム
(50px)
右カラム
(100px)

また、子要素のarticleにflex:1;を設定することにより、親要素のwidthを広げた場合、articleが余白を埋める形で自動で伸縮します。

記事
(自動で伸縮)
左カラム
(50px)
右カラム
(100px)

このように、親要素の幅が広がると、子要素のボックスが自動で伸縮して余白を埋めるため、FlexibleなBoxの意味でFlexboxと呼ばれています。

Flexboxは、基本的には親要素にdisplay:flex;を指定することで、子要素の並びを一括で管理するものです。けれども、より詳細に指定する場合には、上記のorder:1;やflex:1;のように子要素に指定するプロパティもあります。

子要素に指定するプロパティの一覧

上記はいずれもFlexboxの親要素に指定するプロパティですが、子要素に指定するプロパティもあり、主に子要素の伸び縮みや並び順を制御する際などに使用します。

flex(grow、shrink、basisのショートハンド)

flexは子要素の伸縮ルールを指定するプロパティですが、以下のflex-grow(伸びる)、flex-shrink(縮む)、flex-basis(初期サイズ)をまとめて指定する際に使用します。

flex: flex-grow flex-shrink flex-basis;の順番で指定します。

.example {
  flex: flex-grow flex-shrink flex-basis;
}

例えば、「flex:1;」の場合、flex-grow:1;、flex-shrink:1;、flex-basis:0;のショートハンドになります。
同様に、「flex:2;」の場合、flex-grow:2;、flex-shrink:1;、flex-basis:0;です。
あるいは、「flex:100;」の場合、flex-grow:100;、flex-shrink:1;、flex-basis:0;です。

つまり、いずれも「flex-shrink:1;、flex-basis:0;」が省略された形になります。

書いた値 内容 flex-grow flex-shrink flex-basis
flex: X; grow のみ指定 X 1 0
flex: X Y; grow + shrink X Y 0
flex: X Y Z; grow + shrink + basis X Y Z

ショートハンドの項目となるgrow、shrink、basisの具体的な内容は以下をご参照ください。

flex-grow(余白を伸びて埋める比率)

余ったスペースを他の子要素とどれだけの割合で分配するかを指定します。そのため、他の子要素との割合になります。

<div class="example">
  <div class="a">1</div>
  <div class="b">2</div>
  <div class="c">3</div>
</div>
.example {
  display: flex;
  gap:10px;
  width:600px;
  border:2px solid #ccc;
}

.a {flex-grow:2;}
.b {flex-grow:4;}
.c {flex-grow:1;}

.example div {
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
1
2
3

上記の場合、以下のような計算になります。

親要素600px
子要素:40px × 3=120px
gap:10px × 2=20px

余白スペース:600px -120px -20px = 460px

「1」のwidth幅:460px × 2/7=131px+40px=171px
「2」のwidth幅:460px × 4/7=262px+40px=302px
「3」のwidth幅:460px × 1/7=65px+40px=105px

合計:171px + 302px + 105px = 578px
578px + gap(20px) + border(2px)=600px

flex-growの初期値は「0」で伸びないという仕様になります。

このflex-grow値はあくまで他の子要素との比率のため、もし子要素が1つしかない場合には、flex-growの値が1でも10でも100でも、1/1、10/10、100/100で結果は同じになり、いずれも余白いっぱいまで伸びることになります。

上記の3カラムでは、articleにのみ「flex:1;」が指定されていますが、この場合はarticleが余白をすべて埋める形になります。

flex-shrink(親が狭いときに縮む比率)

縮むときにどれだけ縮むかを指定します。つまり、不足したスペースを返す比率になります。そのため、スペースが不足していない場合には機能しません。

.example {
  display: flex;
  gap:10px;
  width:600px;
  border:2px solid #ccc;
}

.a {flex-shrink:2;}
.b {flex-shrink:4;}
.c {flex-shrink:1;}

.example div {
  background: #fd9f7c;
  color: #fff;
  width: 40px;
  text-align: center;
}
1
2
3

flex-shrinkの初期値は「1」で標準的に縮むという意味になりますが、flex-shrink:1;のケースが多いと思います。

flex-basis(子要素の基本サイズ)

基本となる幅をpx、auto、0(widthを無視)などと指定します。flex-basis の初期値は「auto」です。

order(並び順)

上記の3カラムのテンプレートの際に指定したように、子要素の並び順を変更します。

article {
  order: 2;
}
.left {
  order: 1;
}
.right {
  order: 3;
}

align-self(個別の縦揃え)

特定の子要素だけ縦方向の揃え方を変えたい場合に使用します。ただ、align-selfの使用頻度はそれほど多くはありません。