【初心者向け】フレックスボックスの基本とよくある使い方について詳しく解説!

CSS

はじめに

ウェブページのレイアウトを構築する手法は様々です。その中でも、フレックスボックスを使用したレイアウト構築は比較的簡単にレスポンシブデザインを実現できるため、ウェブ制作初心者の方には最適な手法です。

この記事では、フレックスボックスの概要や仕組みについて解説し、よく使われるプロパティやレイアウトのパターンについてご紹介します。

この記事の対象者

  • ウェブ制作初心者の方
  • レスポンシブデザインを学びたい方
  • レイアウトの構築に興味のある方

この記事で学べること

  • フレックスボックスの特徴を理解する
  • フレックスボックスを使ったレイアウト構築
  • レスポンシブデザインでのフレックスボックスの活用法

なぜフレックスボックスが必要なのか

従来のウェブデザインにおいて、要素の配置やレイアウト調整はしばしば複雑な作業となりました。

フレックスボックスの手法が普及する以前では、レイアウトを整える際にfloatプロパティを使用する手法が用いられていました。しかし、この手法には以下のような問題がありました。

  • 回り込みの制御
  • レスポンシブ化が難しい
  • 要素の幅や余白の設定に複雑な計算が必要

floatプロパティは要素を左または右に浮動させ、周囲のコンテンツがその要素を回り込むように配置されます。

意図したレイアウトを構築するには回り込みの制御も行う必要があり、この制御が不完全だとレイアウト崩れを引き起こすため、複雑なレイアウト構築やレスポンシブ対応を困難にさせる要因となっていました。

フレックスボックスの登場

このような問題に対する解決策として、フレックスボックスでのレイアウト構築の手法が用いられるようになりました。

フレックスボックスを使用することで、要素のレイアウトや配置を柔軟に制御することができるようになります。

フレックスボックスの特徴

  • 親子関係による簡潔なレイアウト: フレックスボックスでは、親要素をコンテナとし、その内部の子要素をアイテムとして配置します。
  • これにより、要素の配置と余白をシンプルに制御できます。
  • 伸縮性と配置制御: フレックスボックスはアイテムの伸縮性を持たせることができ、コンテナ内のアイテムの位置調整を簡単に行えます。
  • アイテム間の間隔や配置を柔軟に調整でき、複雑な計算を必要としません。
  • レスポンシブデザインの強化: フレックスボックスを使用することで、異なる画面サイズに対応するレスポンシブデザインの実装が容易になります。
  • メディアクエリと組み合わせて使用することで、様々なデバイスに対して最適なレイアウトを簡単に作成できます。

フレックスボックスの基本

フレックスボックスは、要素を親要素であるフレックスコンテナとその内部の要素であるフレックスアイテムに分けて考えます。

フレックスボックスでアイテムの配置やスペース配分を制御するためには、フレックスコンテナとフレックスアイテムを理解することが重要です。

フレックスコンテナ(親要素)

フレックスコンテナは、要素の直下にある子要素を配置するコンテナとして機能します。

displayプロパティを変更することで、その要素をフレックスコンテナとして扱うことができるようになります。

<div class="flex-container">
  <div class="flex-item">アイテム</div>
  <div class="flex-item">アイテム</div>
  <div class="flex-item">アイテム</div>
</div>
.flex-container {
  display: flex;
}

フレックスコンテナ内のアイテムは、メイン軸クロス軸という2つの軸に沿って配置されます。

デフォルトでは、メイン軸は水平方向(左から右)クロス軸は垂直方向(上から下)を指します。よって、上の例ではフレックスアイテムは横並びになります。

フレックスコンテナのプロパティ

以下は、フレックスコンテナで使われる一般的なプロパティです。

  • display: flex要素をフレックスコンテナとして定義します。
  • flex-directionメイン軸とクロス軸を入れ替えます。
  • justify-contentメイン軸上でアイテムの配置方法を指定します。
  • align-itemsクロス軸上でアイテムの配置方法を指定します。
  • gap:アイテム間の余白を指定します。
  • flex-wrap:アイテムの折り返しを指定します。

これらのプロパティを使用することで子要素の配置や余白を制御できます。

フレックスアイテム(子要素)

フレックスアイテムは、フレックスコンテナ直下に配置されるそれぞれの要素です。

フレックスアイテムとして扱われる要素は、フレックスコンテナ内での配置や順序、サイズ、余白の扱いを制御することができます。

フレックスアイテムのプロパティ

以下はフレックスアイテムで使われる一般的なプロパティです。

  • flex-grow:アイテムが余白を取る際の伸縮性を制御します。
  • flex-shrink:アイテムがコンテナ内で縮む際の伸縮性を制御します。
  • flex-basis:アイテムの初期サイズを指定します。
  • align-self: 個々のアイテムのクロス軸上での配置方法を指定します。
  • order: アイテムの表示順序を変更します。

これらのプロパティは各アイテムに個別で指定することができ、これにより柔軟なレイアウトを実現することができます。

フレックスボックスで出来ること

フレックスボックスの一般的な使い方についてご紹介します。

フレックスボックスを使用することで、主に以下のようなことを実装できます。

  • 均等なスペースの分配
  • アイテムの中央配置
  • 画面幅で配置する方向を変更
  • アイテムをタイル状に並べる
  • ページ全体のレイアウトを構築

それぞれの実装方法について解説します。

均等なスペースの分配

フレックスボックスを使用することで、あらゆる画面幅でも要素間の余白を均等に配置することができます。

以下が例です。

<div class="flex-container">
  <div class="flex-item">アイテム1</div>
  <div class="flex-item">アイテム2</div>
  <div class="flex-item">アイテム3</div>
</div>
.flex-container {
  outline: 1px solid #888;
  display: flex;
  justify-content: space-between;
}
.flex-item {
  outline: 1px dotted #888;
}

要素の大きさを分かりやすくするためにoutlineで線を表示しています。これ以降の例ではoutlineの記述は省略します。

justify-contentプロパティは、メイン軸上でのアイテムの配置方法を指定できます。初期値はflex-startとなっており、アイテムは左揃えで配置されます。

justify-content: space-between;を指定することで、アイテムをコンテナの幅を基準に両端揃えで均等配置することができます。

justify-contentでよく使われる値
  • flex-startアイテムをメイン軸の開始点に配置します。
  • flex-endアイテムをメイン軸の終了点に配置します。
  • centerアイテムをメイン軸上で中央に配置します。
  • space-betweenアイテムを両端揃えで均等配置します。
  • space-aroundアイテムを両端の余白も含めて均等配置します。

アイテムの中央配置

メイン軸とクロス軸を中央に指定することで、コンテナの中央にアイテムを配置することができます。

.flex-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}

align-itemsプロパティは、クロス軸でのアイテムの配置方法を指定できます。初期値はstratchとなっており、アイテムは上揃えで配置され、各アイテムの高さは揃えられます。

この例では、align-items: center;でクロス軸の中央に、justify-content: center;と指定することによりメイン軸の中央にアイテムを配置しています。

また、コンテナの高さは、デフォルトではアイテムの高さに依存します。

align-itemsの指定が有効なケースは主に、「アイテムの高さがそれぞれ違う」「コンテナがアイテム以上の高さを持っている」の2つになります。

コンテナの高さ、アイテムそれぞれの高さが全て同じ場合では、align-itemsを指定する意味がないので注意しましょう。

align-itemsでよく使われる値
  • flex-startアイテムをクロス軸の開始点に配置します。
  • flex-endアイテムをクロス軸の終了点に配置します。
  • centerアイテムをクロス軸上で中央に配置します。

画面幅で配置する方向を変更

レスポンシブ対応を行う際、スマホでは要素を縦に配置し、タブレットやPCでは要素を横並びにしたいという場合が多くあります。

これを実装する方法として一般的にはメディアクエリを使用します。

@media screen and (min-width: 768px) {
  .flex-container {
    display: flex;
  }
}

これで画面幅768px以上の場合のみにアイテムを横並びにすることができます。

このようなケースでは、すでにフレックスアイテムとなる要素にスタイルが指定されている可能性があります。

.flex-item {
  margin-top: 16px;
}

.flex-item:first-child {
  margin-top: 0;
}

この例は、要素が縦に並んでいるときのアイテム間の余白を設定しています。一番上のアイテムはmargin-topが不要なので0で上書きしています。

このスタイルはPCやタブレットでも適用されますが、レイアウト崩れを起こすためリセットする必要があります。

スマホでの表示
PC・タブレットでの表示

また、横並びの時のアイテム間の余白も設定する場合があります。

@media screen and (min-width: 768px) {
  .flex-container {
    display: flex;
  }
  .flex-item {
    margin-top: 0;
    margin-left: 16px;
  }
  .flex-item:first-child {
    margin-left: 0;
  }
}

同じ要素に対してmarginの指定が複数あるため、少し回りくどく感じます。

この問題は、gapプロパティを使用することで簡単に解決することができます。

.flex-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

@media screen and (min-width: 768px) {
  .flex-container {
    flex-direction: row;
  }
}

gapはアイテム間の余白を設定するプロパティで、プロパティ名を「row-gap」や「column-gap」にすることで余白の方向を指定することもできます。

.flex-container {
  …
  row-gap: 16px; /* 水平方向の余白 */
  column-gap: 20px; /* 垂直方向の余白 */
}

gapはフレックスコンテナに指定できるプロパティなので、まずはdisplay: flex;でフレックスコンテナを定義します。

.flex-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

上記の例では、flex-direction: column;の指定で要素を縦に配置しています。

通常のブロック要素で縦に並べた場合との違いはいくつかあるのですが、ここではgapプロパティを扱う目的でこのように指定しています。

また、flex-direction: row;とすることでメイン軸を水平方向に戻すことができます。

@media screen and (min-width: 768px) {
  .flex-container {
    flex-direction: row;
  }
}

gapはアイテム間の余白のみに適用されるので、marginでの余白指定のように余計なリセットは必要ありません。

結果は同じ表示でも、コードの記述量を減らすことができます。

.flex-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

@media screen and (min-width: 768px) {
  .flex-container {
    flex-direction: row;
  }
}
.flex-item {
  margin-top: 16px;
}

.flex-item:first-child {
  margin-top: 0;
}

@media screen and (min-width: 768px) {
  .flex-container {
    display: flex;
  }

  .flex-item {
    margin-top: 0;
    margin-left: 16px;
  }

  .flex-item:first-child {
    margin-left: 0;
  }
}
flex-directionでよく使われる値
  • rowアイテムを水平方向に配置します(デフォルト値)。
  • row-reverseアイテムを水平方向に逆順に配置します。
  • columnアイテムを垂直方向に配置します。
  • column-reverseアイテムを垂直方向に逆順に配置します。

アイテムをタイル状に並べる

アイテムをタイル状に並べるにはグリッドシステムを使う方が適切ですが、フレックスボックスでも工夫次第で実装できます。

フレックスボックスはアイテムを折り返して配置することもできます。flex-wrapプロパティを使用することで、アイテムをタイル状に並べることが可能となります。

<div class="tile-container">
  <div class="tile-item">1</div>
  <div class="tile-item">2</div>
  <div class="tile-item">3</div>
  <div class="tile-item">4</div>
  <div class="tile-item">5</div>
  <div class="tile-item">6</div>
  <div class="tile-item">7</div>
  <div class="tile-item">8</div>
  <div class="tile-item">9</div>
</div>
.tile-container {
  display: flex;
  flex-wrap: wrap;
}

.tile-item {
  flex-grow: 1;
  flex-basis: 33%;
  aspect-ratio: 1/1;
  background-color: #f0f0f0;
}

この例では、9つのアイテムを「3×3」のタイル状に並べています。以下のように表示されます。

flex-wrapはアイテムの折り返しを指定します。

デフォルト値はnowrapとなっており、フレックスコンテナ内のアイテムは、折り返されずに縮小されて全て横並びになります。

flex-wrap: wrap;を指定することで、アイテムがコンテナ幅を超えた場合に折り返すように設定することができ、これによりフレックスアイテムを複数行で配置することができます。

flex-wrap: wrap;の使い方として、アイテムに対して幅指定をする必要があります。上の例ではflex-basisプロパティで指定していますがwidthで指定しても構いません。

アイテムの幅は33%と指定していますが、flex-grow: 1;の指定によって各アイテムは親要素いっぱいに等しく広がります。

.tile-item {
  flex-grow: 1;
  flex-basis: 33%;
  aspect-ratio: 1/1;
  background-color: #f0f0f0;
}

flex-growはコンテナの余白をどのように扱うかを設定するためのプロパティであり、初期値は0です。上記の例では.tile-itemすべてにflex-grow: 1;が適用されるため、各アイテムの幅に等しく余白が分配されます。

アイテムの幅を34%にすると、3列分のアイテムの合計幅が100%を超えるため、タイルは2列になります。また、25%にすると4列で配置することができます。

また、アイテムの高さはaspect-ratio: 1/1;とすることでアイテムの幅と同じになるように設定しています。

widthとflex-basisの違い

widthとflex-basisの違いについて簡単に解説します。

上記の例では、flex-basisはアイテムの幅を指定する目的で使用していますが、この例ではwidthで指定しても何も変わりません。しかし、メディアクエリなどでflex-direction: column;を指定した場合は大きな違いがあります。

widthで指定した場合、アイテムの幅はそのままwidthの値が適用されますが、flex-basisで指定した場合はflex-basisの値がアイテムの高さとして適用されます。

同様に、flex-direction: column;の状態で指定したflex-basisの値はアイテムの高さとして適用されますが、flex-direction: row;に変化した場合はアイテムの幅として扱われることになり、heightでアイテムの高さを指定した場合は横並びになってもheightの値が適用されます。

この記事ではプロパティの説明のためにflex-basisを使用しましたが、フレックスアイテムには幅や高さの指定にflex-basisを使わなければいけないという意味ではありません。

widthやheightとの違いを理解した上でflex-basisを使用しないと、予期せぬレイアウト崩れを起こす可能性があるので注意しましょう。

ページ全体のレイアウトを構築

フレックスボックスはアイテムの伸縮性を制御することができるため、ウェブページのレイアウト構築を容易にします。

ウェブページのレイアウトを構築する際、レスポンシブデザインについても考える必要があります。

画面幅の変更により影響を受ける要素を決定し、必要であれば要素単位で固定幅や最小幅、最大幅などを設定することで、どのような画面幅でも整ったレイアウトになることを目指します。

ウェブページのレイアウト構築は、フルードレイアウト(可変幅レイアウト)固定幅レイアウトの2つの手法があります。

フルードレイアウト

フルードレイアウトは、ウィンドウの幅に応じて要素の幅を自動的に調整するアプローチです。

フレックスボックスを使用してフルードレイアウトを構築する場合のシンプルな例をご紹介します(レイアウトに関わる内容のみ記述しています)。

<header class="header">
  <h1><a href="#">header</a></h1>
</header>

<div class="contents-wrapper">

  <main class="main-contents">
    <h2>メインコンテンツ</h2>
    <p>メインコンテンツが入ります。</p>
  </main>

  <aside class="sub-contents">
    <h2>サイドバー</h2>
    <section>
      <h3>オススメのメニュー</h3>
      <ul>
        <li><a href="#">リスト</a></li>
        <li><a href="#">リスト</a></li>
        <li><a href="#">リスト</a></li>
        <li><a href="#">リスト</a></li>
      </ul>
    </section>
  </aside>

</div>

<footer class="footer">footer</footer>
.contents-wrapper {
  max-width: 1060px;
  margin: 0 auto;
  display: flex;
}

.main-contents {
  flex-grow: 3;
}

.sub-contents {
  flex:-grow 1;
}

この例では、main要素とaside要素を「contents-wrapper」というクラス名を付けたdiv要素で囲っています。

.contents-wrapperをフレックスボックスにすることでmain要素とaside要素を横並びにしています。

.contents-wrapper {
  max-width: 1060px;
  margin: 0 auto;
  display: flex;
}
<header class="header">…</header>
<div class="contents-wrapper">

  <main class="main-contents">…</main>
  <aside class="sub-contents">…</aside>

</div>
<footer class="footer">…</footer>

注意点として、フルードレイアウトは親要素や画面幅を基準に要素幅が可変します。サイドバーのような幅が狭いコンテンツでは、画面幅によってはレイアウト崩れが起きる可能性があります。

各フレックスアイテムにはflex-growプロパティを指定しており、この値によってフレックスコンテナが持っている余白の分配を制御しています。

.main-contents {
  flex-grow: 3;
}

.sub-contents {
  flex:-grow 1;
}

.main-contentsにはflex-grow: 3;を、.sub-contentsにはflex-grow: 1を指定しており、main-contentsはsub-contentsの3倍の余白が割り当てられることになります。

flex-growプロパティの値は、画面幅による各アイテムへの影響の強さを表しています。

.main-contents側のflex-growの値が大きければ大きいほど、画面幅の縮小による.sub-contents側への影響が少なくなり、結果的に.sub-contentsのレイアウト崩れのリスクが下がります。

また、.contents-wrapperに指定されたmax-widthプロパティの役割は、想定以上に大きなディスプレイで表示された場合の対策になります。

.contents-wrapper {
  max-width: 1060px;
  margin: 0 auto;
  display: flex;
}

あまりにも横幅の広いウェブページは可読性を損なうため、一般的なウェブページはコンテンツの最大幅に制限をかけます。margin: 0 auto;で左右中央揃えの指定も忘れずに行いましょう。

固定幅レイアウト

固定幅レイアウトでは、サイドバーやコンテンツ、あるいはページ全体を固定幅で指定します。画面幅が変わっても要素の幅が変わらないため、スタイル崩れを許容できない場合に有効です。

フルードレイアウトで使用したHTMLを参考にすると、固定幅レイアウトは以下のパターンが考えられます。

メインコンテンツサイドバー
パターン1可変固定
パターン2固定固定

まずはパターン1のシンプルな例をご紹介します。

パターン1
  • メインコンテンツ:可変
  • サイドバー:固定
.contents-wrapper {
    display: flex;
    justify-content: center;
}

.main-contents {
    flex: 1 1 auto;
}

.sub-contents {
    flex: 0 0 200px;
}

flexプロパティは、flex-grow、flex-shrink、flex-basisの3つを一括指定するためのプロパティです。値指定の順番は以下になります。

flex: flex-grow flex-shrink flex-basis;

値は必ず3つ指定しなければいけないというわけではありませんが、3つ指定したほうが分かりやすくて親切でしょう。

サイドバーから解説します。

.sub-contentsにはflex: 0 0 200px;が指定してあるため、200pxは要素の幅であることが分かります。また、.sub-contentsのflex-growとflex-shrinkは共に「0」を指定しています。

.sub-contents {
    flex: 0 0 200px;
}

flex-shrinkプロパティは、コンテナ幅がアイテムの合計幅より小さくなった場合のアイテムの縮小比率を指定するプロパティです。flex-shrinkはデフォルトで1が設定されており、各アイテム幅は自動的にコンテナをはみ出さないように調整されます。

flex-shrinkの値を0にすることで、フレックスボックスによるアイテム幅の自動調整が作用しなくなり、フレックスアイテムの固定幅を実現できます。

次に、メインコンテンツについて解説します。

.main-contentsにはflex: 1 1 auto;という指定をしています。

.main-contents {
    flex: 1 1 auto;
}

フレックスアイテムは.main-contentsと.sub-contentsしかないため、画面幅によるフレックスボックスの影響の全ては.main-contentsが受けることになります。

つまり、画面幅が1px変われば同じだけ.main-contentsの幅が変わります。

続いてパターン2について解説します。

パターン2
  • メインコンテンツ:固定
  • サイドバー:固定

メインコンテンツとサブメニューの両方を固定幅にする場合、画面幅の変化を要素側で吸収することができません。

つまり、画面幅よりもコンテンツ幅が大きい場合に横スクロールが発生してしまいます。

この対策として、画面幅との差異を左右の余白に吸収させることでレスポンシブ化を行います。

/* スマホ兼共通のスタイル */
.contents-wrapper {
    display: flex;
    flex-direction: column;
}

/* タブレットのスタイル */
@media screen and (min-width: 768px) {
    .contents-wrapper {
        flex-direction: row;
        margin: 0 auto;
        max-width: calc(768px - 20px);
    }
    .main-contents {
        width: 70%;
    }
    .sub-contents {
        width: 30%;
    }
}

/* PCのスタイル */
@media screen and (min-width: 1080px) {
    .contents-wrapper {;
        max-width: calc(1080px - 20px);
    }
}

この例では、.contents-wrapperに対してブレイクポイント毎にmax-widthを指定しています。

/* タブレットのスタイル */
@media screen and (min-width: 768px) {
    .contents-wrapper {
        …
        max-width: calc(768px - 20px);
    }
    …
}

/* PCのスタイル */
@media screen and (min-width: 1080px) {
    .contents-wrapper {;
        max-width: calc(1080px - 20px);
    }
}

max-widthの値はcalc関数を使用しており、ブレイクポイントよりも20px低い値を設定しています。これにより、ブレイク直前での左右の余白を10pxずつ確保しています。

また、ブレイクポイント768px以上では、.main-contentsとsub-contentsのwidthを%で指定しています。

/* タブレットのスタイル */
@media screen and (min-width: 768px) {
    …
    .main-contents {
        width: 70%;
    }
    .sub-contents {
        width: 30%;
    }
}

各アイテムのwidth指定に%を使用することで、各ブレイクポイント共通の比率でアイテムに固定幅を指定することができます。

.sub-contentsの幅をブレイクポイント毎に変化させたくない場合は、calc()関数を使用してwidthを指定します。

/* タブレットのスタイル */
@media screen and (min-width: 768px) {
      …
    }
    .main-contents {
        width: calc(100% - 200px);
    }
    .sub-contents {
        width: 200px;
    }
}

上の例は、.main-contentsのwidthに対し、コンテナ全体の幅からサイドバーの幅を引いた値を指定しています。

固定幅レイアウトはレイアウト崩れに強く、デザインの再現性が高いという特徴がありますが、レスポンシブ対応に手間が掛かることやコードが煩雑になりやすいというデメリットもあります。

最後に

フレックスボックスの概要、仕組み、よく使われるプロパティやレイアウトのパターンについて解説しました。

フレックスボックスには他にも扱えるプロパティがたくさんあり、プロパティを指定することでさまざまなレイアウトを実現することができます。

フレックスボックスに慣れていない方は、この記事でご紹介したコードを組み合わせて一つのウェブページを作ってみると理解が深まるでしょう。

タイトルとURLをコピーしました