当社TORICO の社内勉強会で CSS のフレックス( display: flex ) の演習を行いました。 この記事は、その勉強会で行ったフレックスの演習の内容を公開するものです。
演習の内容
HTML のウェブアプリとして、上部に固定ヘッダー、下部に固定フッター、中央左にナビ、中央右にメインコンテンツがあるサイトを想定して CSS を書きます。

CSS の書かれていない HTML に CSS を書いていき、目標画像と同じ見た目になるようにします。
なお、この記事ではフレックスの基本的な属性の意味については説明していません。 必要に応じて、MDN 等を見てください。
完成した HTML
最終的に以下の HTML になります。
CSSフレームワーク
当社では、通常は CSS フレームワークの使用を推奨しています。 ページレイアウトを行う際は Bootstrap や Tailwind などのフレームワークが使われることが多いですが、今回は演習のため CSS フレームワークは使いません。
ただし、アイコンを表示するために Bootstrap Icons を使用します。
そのほかのレイアウト方法との比較
ページ全体をレイアウト(段組み)する方法として、HTML4の時代は float を使ったり、 position: absolute を使ったり、それ以前は table を使ったレイアウトもありました。 しかし、フレックスの登場で、それらを ページレイアウトで 使う必要は無くなりました。
フレックスを使うことで、あらゆるレイアウトを直感的に、少ない記述で美しくレイアウトができます。業務上必須となるため、慣れていない方は十分練習をしてください。
グリッドとの比較
同時期に策定された display: grid; (グリッドレイアウト)も、よく使われるレイアウト手法です。 サイト全体をグリッドでレイアウトすることもできますが、複数行x複数列のグリッドを作ると各要素の設定が疎にならないため、最初はいいのですが後から修正を行う際に複雑になりがちですので、採用するにあたり十分考慮したほうが良いと思います。
今回の記事ではグリッドについては触れません。
フレックスのレイアウトの基本的な考え方
フレックスは、内容を縦横自由に、柔軟に並べることができます。
そのため、まずは理想とするレイアウトをイメージし、その中で何がどの方向で並んでいるかを意識する必要があります。
まず、今回のレイアウトでは、まず一番大きく並んでいる要素は、ヘッダー、中央コンテンツ、フッターです。 そのため、それらのを含む親要素は、子要素を縦に並ばせるフレックスコンテナーとします。

ヘッダーの中を見ると、左上の地球儀のアイコン、サイト名、右上のお知らせや設定ボタンが横並びになっているので、ヘッダーは子要素を横に並ばせるフレックスコンテナーとし、

さらに、お知らせアイコンとその下のテキストは、縦並びになっているので子要素を縦に並ばせるフレックスコンテナーにしてレイアウトを作ります。

同じように、中央コンテンツは、ナビとメインコンテンツが横並びになっているので、子要素を横に並ばせるフレックスコンテナーを作ります。

フッターも、「サイトフッター」という文言と「連絡する」の文言が横にならんでいるため、子要素を横に並ばせるフレックスコンテナーにします。

演習
1. 課題HTMLをコピーして開く
課題HTML をコピーし、Mac 内に .html のファイルとして保存してください。
保存後、ブラウザで開いてください。

2. ヘッダーを作り込む
まずは、ヘッダーから作り込んでいきます。
本来は、一番外側の要素 (body) から作り込んでいくのが良いと思いますが、 今回の課題は、フッターを下部に固定する箇所が、他の要素を作りこないと挙動がわかりにくいため、 一番外側の body のレイアウトは最後に行います。
header の中には .header-left と .header-right の2つのエレメントが入っています。 これらを横並びにするため、 header に display: flex; を指定します。
header {
background-color: royalblue;
color: white;
display: flex; /* これを追加 */
}
これを指定しただけだと、右側に無駄な余白ができてしまいます。

中央に余白を作るためには、 header に justify-content: space-between; を設定するか、 .header-left に flex-grow: 1; を設定します。
それぞれ意味が違いますが、今回はどちらでもOKです。今回は、justify-content: space-between; を使います。
header {
background-color: royalblue;
color: white;
display: flex;
justify-content: space-between;
}

ヘッダー内部を作り込みます。
.header-left, .header-right もそれぞれフレックスコンテナーとして、さらに右上部のメニューアイテムもフレックスコンテナーとします。
フォントサイズやパディングを調整し、完成したヘッダー部分の CSS は以下のようになります。
header {
background-color: royalblue;
color: white;
display: flex;
justify-content: space-between;
.header-left {
padding: 0.5em;
font-size: 1.5em;
}
.header-right{
display: flex;
gap: 1em;
justify-content: center;
align-items: center;
padding: 0.5em 1em;
.header-menu-item {
display: flex;
gap: 0.2em;
align-items: center;
flex-direction: column;
.header-menu-text {
font-size: 0.5em;
}
}
}
}

3. 中央コンテンツを作り込む
中央コンテンツ の .body-container を作り込んでいきます。 これも内容を横に並ばせるフレックスコンテナーにするので、display: flex; を指定します。
.body-container {
display: flex; /* 追加 */
nav {
background-color: #ddd;
}
main {
}
}
そのままだと、nav の幅が狭いため、サイズを指定します。今回は、 width: 20em; を指定します。 width: 300px; 等の指定でも OKです。
.body-container {
display: flex;
nav {
background-color: #ddd;
width: 20em; /* 追加 */
}
main {
}
}

一見大丈夫そうですが、このままでは少し問題があります。main の背景色と html の背景色が同じでわかりにくいのですが、現在 main の中身は、横幅が自動調整され、ページの右端まで使われていません。
試しに、 main に background-color: yellow; を指定してみた例が以下の画像です。

このままでは、コンテンツが横に長くなった場合に問題が発生しやすいため、 main は幅いっぱいまで使うようにします。
そのためには、 main に flex-grow: 1; を指定します。
ついでに適当に padding も設定し、 完成した .body-container の CSS は以下のようになります。
.body-container {
display: flex; /* 追加 */
nav {
background-color: #ddd;
width: 20em;
padding: 1em;
}
main {
flex-grow: 1; /* 追加 */
padding: 1em;
}
}
この状態では、まだ main の内容がスクロールするボックスの中に収まっていませんが、一旦次へ進みます。
3. フッターを作り込む
要素を横に並べるため、footer にも display: flex; を設定し、中央に余白を入れるため justify-content: space-between; を設定します。
padding 等を調整し、footer の CSS は以下のようになります。
footer {
background-color: #bbb;
font-size: 0.85em;
display: flex; /* 追加 */
justify-content: space-between; /* 追加 */
.footer-left {
padding: 0.5em;
}
.footer-right {
padding: 0.5em;
}
}

4. 全体のレイアウトを作る
不足しているレイアウトを整えていきます。
bodyにdisplay: flex;を指定。header,.body-container,footerを一つのフレックスコンテナーにいれるため。bodyにflex-direction: column;を指定。子要素を縦に並べるため。bodyにheight: 100%;を指定。bodyの高さを制限するため。mainにoverflow-y: auto;を指定。収まらない部分をスクロールさせるため。.body-containerにflex-grow: 1;を指定。サイズを可変にするため。.body-containerにmin-height: 0;を指定。直感的にかなりわかりにくいですが、 この指定を行わない限り、main の天地サイズがうまく適用されません。
完成した、 body と .body-container の CSS は以下のようになります。
body {
margin: 0;
padding: 0;
display: flex;
height: 100%;
flex-direction: column;
}
.body-container {
display: flex;
flex-grow: 1;
min-height: 0; /* なぜか必要 */
nav {
...
これで、期待通りの表示がされました。

最後に、HTML の全文を以下に掲載します。