Flexbox を利用した Sinlge Page Application のレイアウト

Flexbox

こんにちは。スタメンでデザイナー兼フロントエンドエンジニアをしているナガキです。

弊社が提供している「TUNAG」 には(オプションで)ビジネスチャット機能があります。

App版チャット
App版チャット

PC版チャット
PC版チャット

ご覧のように、スマホアプリ版は非常にシンプルな画面構成ですが、PC版はひとつの画面内に様々な情報を表示する必要があり、どうしても複雑になりがちです。
そんな複雑で大量の情報を CSS の Flexbox を利用してレイアウトしています。

今回は「TUNAG」PC版チャットを例に、Flexbox の便利な使い方をご紹介します。

Flexbox とは

Flexible Box Layout Module のことで、Flex Container と呼ばれる親要素と Flex Item と呼ばれる子要素を使って、柔軟なレイアウトが実現できます。

CSS Flexible Box Layout – MDN web docs

仕様が何度も変わったり、ブラウザが対応していないなどの問題もありましたが、現在ではほとんどすべてのモダンブラウザで安心して利用することができます。

Can I use

最近徐々に利用が広がっている Grid Layout は2次元のレイアウトを定義しますが、Flexbox は1次元、つまり横か縦、どちらか一方向だけのレイアウト(並びや余白)を定義します。
これだけ聞くと Grid Layout のほうが便利なように思えますが、Flexbox をうまく活用することで、その名のとおりフレキシブルなレイアウトが実現できます。

それでは早速、実際のチャット画面を参考にしながら、どのように Flexbox を利用しているか説明していきましょう。

固定幅 + 可変幅の横方向カラムレイアウト

PC版チャットのベースレイアウトは

位置 コンテンツ 横幅 ウィンドウサイズによる拡縮
ルーム一覧 固定 なし
中央 選択中ルームのメッセージ一覧 可変 あり
選択中ルームに関する情報 固定 なし

となっており、左右のカラムが固定幅、中央のメッセージ一覧部分だけがウィンドウ幅にあわせて変わります。

これを CSS で実装しようとすると以下のようになります。

See the Pen flexbox sample 1 by ngk works (@ngk-works) on CodePen.

flex プロパティでカラムの拡縮をコントロールする

ポイントとなるのは子要素の flex プロパティ。これでカラム幅の拡縮の有無(flex-grow, flex-shrink)や基準幅(flex-basis)をまとめて設定しています。


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

サンプルでは左右のカラムを 100px の拡縮しない要素とすることで、中央のカラム幅だけがウィンドウ幅に応じて変わるようになります。

このように Flexbox を利用することで、複数カラムのレイアウトが簡単に実現できました。

固定幅 + 可変幅の縦方向カラムレイアウト

Flexbox は横方向だけでなく、縦方向にも利用できます。

例えば、左カラムにあるチャットルーム一覧部分のレイアウトを見てみると、

コンテンツ 高さ ウィンドウサイズによる拡縮 スクロール
ヘッダ(タイトル) 固定 なし なし
検索フォーム 可変(なりゆき) なし なし
ルーム一覧 可変(なりゆき) あり あり

となっています。

先程のベースレイアウトと比べると、

  • コンテンツが並ぶ方向が縦
  • 拡縮はしないが、コンテンツの内容によって幅(高さ)が決まるコンテンツがある
  • ウィンドウ幅やコンテンツの内容によって幅(高さ)が変わる

という違いがありますが、これも Flexbox であれば簡単に実装できます。

See the Pen flexbox sample 2 by ngk works (@ngk-works) on CodePen.

flex-direction で並べる方向を指定する

flex-directioncolumn に指定するだけで Flex Item を縦方向に並べることができます。
また、幅をコンテンツ内容に合わせたい場合は flex-basisauto を指定します。


.flex-container--column {
  display: flex;
  flex-flow: column nowrap;   // 縦方向に並べる
}

.component-header {
  flex: 0 0 60px;   // 拡縮なし / 固定幅
}

.search-form {
  flex: 0 0 auto;   // 拡縮なし / コンテンツに応じた幅
}

縦方向に並べる場合に気をつけなければならないのは、ウィンドウの高さとコンテンツ量の関係です。
コンテンツ量がそれほど多くなく、ウィンドウ内に収まる場合は問題ありませんが、ウィンドウの高さを超える量のコンテンツがある場合は注意が必要です。

「TUNAG」のチャットでは1画面内にすべての情報を収める必要があるため、チャットルーム一覧部分が画面外に広がっていかないよう


.room-list {
  overflow-y: auto;
}

を指定することで、状況に応じてリスト部分だけをスクロールさせています。

サンプルのウィンドウサイズを変えたり、リストアイテムの数を増減させたりして挙動を確認してみてください。

Flexbox を利用して、思い通りのレイアウトを実現する

右カラムにはチャットルームの様々な情報が表示されています。

コンテンツ 高さ ウィンドウサイズによる拡縮 スクロール 配置
ルームアイコン 固定 なし なし
メンバー一覧 可変(なりゆき) あり あり
ファイル一覧 可変(なりゆき) なし なし

(※ 各コンテンツには、指定幅のヘッダ(タイトル)と実コンテンツが含まれます)

チャットルーム一覧とは

  • 下寄せで配置されるコンポーネントがある
  • 大きさの違う複数個のコンポーネントが混在する

という違いがあります。

flex プロパティを利用してカラム位置をコントロールする

コンポーネントの下寄せ配置は、拡縮可能なコンテンツを利用することで実現します。

See the Pen flexbox sample 3 by ngk works (@ngk-works) on CodePen.

上記のサンプルでは


.members {
  flex: 1 1 auto;
}

により、中央のメンバー一覧部分がウィンドウ領域を埋めるように拡縮するため、ファイル一覧が最低限の高さを確保した状態で、最下部に押しやられます。

margin プロパティを利用してカラム位置をコントロールする

また別の手段として、margin を利用する方法もあります。

例えば、下記のようなメンバー一覧部分が拡縮しない場合であっても、


.members {
  flex: 0 0 auto;
}

margin を利用することで、下寄せ配置が実現できます。


.files {
  flex: 0 0 auto;
  margin-top: auto;      
}

Flex Container をネストすることでスクロールをコントロールする

「TUNAG」PC版チャットでは、コンテンツの高さがウィンドウの高さを超えた場合にメンバー一覧だけをスクロールさせる必要がありました。

See the Pen flexbox sample 4 by ngk works (@ngk-works) on CodePen.

ポイントとなるのは、.members.flex-container--columnFlex Item であり、.member-listFlex Container でもある点です(.files も同様)。

FlexboxFlex Container をネスト(入れ子構造)することができるため、うまく利用すると、

  • 拡縮の可否
  • スクロールの有無
  • 配置(寄せ)

などを自由自在に組み合わせることができます。

サンプルでは、メンバー一覧のリスト部分だけを拡縮・スクロール可能な要素とすることで、1画面に収めつつ、状況に応じてスクロールバーを表示しています。

Flexbox で柔軟なレイアウトを

冒頭に

Grid Layout のほうが便利なように思えますが、
Flexbox をうまく活用することで、その名のとおりフレキシブルなレイアウトが実現できます

といった理由が、前項の 自由自在な組み合わせ にあります。

Grid Layout はピクセルや割り合いを事前に定義する必要があり、(縦/横)幅が異なるコンテナが混在する場合はレイアウトが難しくなってしまいますが、Flexbox であれば、ピクセルや割り合いを事前に定義することはもちろん、コンテンツに応じた大きさにもできます。

それらを柔軟に組み合わせることができるため、非常に自由度が高いレイアウトが実現できます。

See the Pen flexbox sample 5 by ngk works (@ngk-works) on CodePen.

レイアウトの実装に困ったら、ぜひ Flexbox を使ってみてください。