In 'n' Out

知識を取り込み、そして発信する

1次元レイアウト

Flex(1方向レイアウトの基本)とは

Flexbox(flex)は、要素を横方向または縦方向の一方向に整列させるためのレイアウト手法で、1次元レイアウトと呼ばれます。
要素のサイズや数が変わっても、間隔の調整や中央寄せなどを柔軟に行えます。
positionが「座標」を扱うのに対し、flexは並び方のルールを扱います。

flexの基本構造

flexは親要素と子要素で役割が分かれています。

構文

セレクタ{
    display:flex;
}

display: flex;は要素をフレックスコンテナにし、子要素はフレックスアイテムとして扱われます。
デフォルトでは子要素が横方向に整列されます。

コード例

<div>
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
    <p>要素4</p>
</div>
div{
    display: flex;
}

出力例

要素1

要素2

要素3

要素4

display:flex以外に何も指定していませんが、横並びになりました。
一見当然に見えますが、pはブロック要素なので、通常横には並べることができません。
このように要素の特性に関係なく1方向に並べられるため、リストを横並びにすることもできます。

flex-direction

フレックスコンテナ内の子要素がどの方向に並ぶかを決めるプロパティです。
横方向か縦方向かを切り替えたり、順序を反転させることもできます。

構文

セレクタ{
    flex-direction:値;
}

値にはrow・column・row-reverse・column-reverseの4つがあります。
rowはデフォルトでの横並びなので指定することは少ないですが、columnは縦に並べられ、-reverseで並び順を逆にできます。
当然のことですが、display:flexを指定しないと並びを変えられません。

コード例

<div class="column">
    <span>要素1</span>
    <span>要素2</span>
    <span>要素3</span>
    <span>要素4</span>
</div>
<div class="row-reverse">
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
    <div>
        <h4>要素4</h4>
        <p>入れ子にも対応できます</p>
    </div>
</div>
<div class="row-width">
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
    <p>要素4</p>
    <p>要素5</p>
</div>
.column {
    display: flex;
    flex-direction: column;
}

.row-reverse {
    display: flex;
    flex-direction: row-reverse;
}
        
.row-width{
    display: flex;
}

.row-width p {
    width: 25%;
    border: 1px solid #000000;
}

出力例

要素1 要素2 要素3 要素4

要素1

要素2

要素3

要素4

入れ子にも対応できます

要素1

要素2

要素3

要素4

要素5

1つ目はcolumnを指定したため、インライン要素を縦に並べられます。
2つ目はrow-reverseで順序を逆にしましたが、右から並ぶだけの挙動になるため、意図したレイアウトにならないことも多く、widthなどを使う必要があります。
3つ目は段落にwidthを25%で指定しましたが、要素は5つあります。
しかし本来は5つならwidthは20%なはずなのに、自動でwidthが調整されて5つ横並びになります。

flex-wrap

フレックスコンテナ内の子要素が横幅や縦幅を超えた場合に、折り返して表示するかどうかを制御するプロパティです。
要素が増えてもレイアウトを崩さず整列させられます。

構文

セレクタ{
    flex-wrap:値;
}

flex-wrapはフレックスアイテムを1行に収めるか複数行に折り返すかを指定します。
nowrapがデフォルトで折り返しなし、wrapは通常の順序で折り返し、wrap-reverseは逆順で折り返します。
flex-directionの出力例3つ目の問題はこれで解決できます。

コード例

<div class="wrap">
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
    <p>要素4</p>
    <p>要素5</p>
    <p>要素6</p>
</div>
.wrap {
    display: flex;
    flex-wrap: wrap;
}

.wrap p {
    width: 25%;
    border: 1px solid #000000;
    box-sizing: border-box;
}

出力例

要素1

要素2

要素3

要素4

要素5

要素6

flex-shrinkの影響でアイテムが縮小して1行に収まります。
nowrapを指定するか、指定をしなかった状態では横スクロールが発生するか、アイテムが縮小して1行に収まります。
flex-directionで説明したwidth:25%でも並び続けた要素も、flex-wrapを使うことで解決できます。
折り返しを使うことでレスポンシブ対応も簡単になります。

flex-flow

flex-flowは、flex-directionとflex-wrapをまとめて指定できるプロパティです。
要素の並び方向と折り返しの有無を同時に決められるため、flexレイアウトの基本設定を簡潔に記述できます。

構文

セレクタ{
    flex-flow:flex-directionの値 flex-wrapの値;
}

flex-flowは、1つ目の値で並び方向を、2つ目の値で折り返しの挙動を指定します。
flex-directionとflex-wrapを個別に書いた場合と挙動は同じで、指定をまとめられる点が特徴です。
どちらか一方だけを指定した場合は、指定されなかった側に初期値が適用されます。

コード例

<div>
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
    <p>要素4</p>
    <p>要素5</p>
    <p>要素6</p>
</div>
div{
    display: flex;
    flex-flow: row wrap;
    background-color:#eeeeee; 
}

p {
    width: 25%;
    border: 1px solid #000000;
    box-sizing: border-box;
}

出力例

要素1

要素2

要素3

要素4

要素5

要素6

要素は横方向に並び、横幅が足りなくなると次の行に折り返されます。
flex-flowを使うことで、並び方向と折り返しの意図を1行で表現でき、レイアウトの前提条件を読み取りやすくなります。
flex-directionやflex-wrapを理解したうえで使うと、コードの意味が明確になります。
なお、flex-flowは、方向と折り返しを常にセットで指定したい場合に向いています。
一方で、どちらか一方だけを変更したい場合は、flex-directionやflex-wrapを個別に指定したほうが調整しやすくなります。

gap

フレックスコンテナやグリッドコンテナ内の子要素間の間隔をまとめて指定できるプロパティです。
個別にmarginを設定する必要がなく、均等なスペースを簡単に作れます。

構文

セレクタ{
    gap:値;
}

gapは子要素間のスペースを一括で指定します。
1つの値で行方向・列方向両方に適用され、2つの値を指定すると1つ目が行方向、2つ目が列方向に適用されます。
pxやem、%など任意の長さ単位を指定可能です。
flexコンテナでもグリッドコンテナでも使用できます。

コード例

<div>
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
    <p>要素4</p>
    <p>要素5</p>
    <p>要素6</p>
</div>
div{
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    background-color:#eeeeee; 
}

p {
    width: 25%;
    border: 1px solid #000000;
    box-sizing: border-box;
}

出力例

要素1

要素2

要素3

要素4

要素5

要素6

子要素間に10pxの隙間が自動で挿入され、均等なスペースが確保されています。
個別にmarginを指定する必要がなく、要素の数が変わっても自動で間隔が保たれます。 gapは次ページで扱うgridでも同様に使用できます。

flex-grow

フレックスコンテナ内に余白がある場合に、子要素がどの割合で伸びるかを指定するプロパティです。
実務で最も使用頻度が高く、flexレイアウトの基本となります。

構文

セレクタ{
    flex-grow:数値;
}

flex-growは余っているスペースをどの割合で分け合うかを指定します。
数値は比率として扱われ、同じ値を持つ要素同士は均等に伸びます。
0を指定すると伸びず、1以上を指定すると他の要素と比べて余白を受け取ります。
余白とは、コンテナのサイズから要素の合計サイズを引いた残りのスペースです。

コード例

<div>
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
</div>
div{
    display: flex;
    flex-wrap: wrap;
    background-color:#eeeeee; 
}

p {
    width: 25%;
    border: 1px solid #000000;
    box-sizing: border-box;
}
        
p:first-child {
    flex-grow: 1;
}

p:nth-child(2) {
    flex-grow: 2;
}
        
p:last-child {
    flex-grow: 1;
}

出力例

要素1

要素2

要素3

要素2はflex-growの値が要素1・3より大きいため、他の要素より多くの余白を受け取り、要素1:要素2:要素3=1:2:1の比率になります。
flex-growを同じ値に揃えると均等割りになり、比率を変えるだけでレイアウトのバランスを直感的に調整できます。
幅指定をせずに可変レイアウトを作れる点が大きな特徴です。

flex(ショートハンド)

フレックスアイテムの伸び方・縮み方・基準サイズをまとめて指定できるショートハンドプロパティです。
個別指定を省略したい場合に使用します。

構文

セレクタ{
    flex:値;
}

flexはflex-grow・flex-shrink・flex-basisを一括で指定するショートハンドです。
1つの数値だけを指定した場合はflex-growとして扱われ、残りの値には初期値が自動的に補われます。
よく使われるflex:1は、余白を均等に分け合う指定になります。

flex-shrinkはコンテナが狭くなったときにどれだけ縮むかを制御します。
flex-basisは伸縮計算の基準となるサイズです。
これらは通常初期値のまま使われることが多く、実務ではflex-growのみを意識するケースがほとんどです。

コード例

<div>
    <p>要素1</p>
    <p>要素2</p>
    <p>要素3</p>
</div>
div{
    display: flex;
    flex-wrap: wrap;
    background-color:#eeeeee; 
}

p {
    flex: 1;
    border: 1px solid #000000;
    box-sizing: border-box;
}

出力例

要素1

要素2

要素3

すべての子要素にflex:1を指定することで、コンテナ内の余白が均等に分配されます。
flex-growを個別に指定しなくても簡潔に書ける点が利点ですが、詳細な制御が不要な場合はflex-grow単体でも十分対応できます。
ショートハンドは仕組みを理解したうえで使うと効果的です。