はじめに#
Flexboxの基本概念やプロパティを学んだ後、「実際の業務ではどのように使うのか」という疑問を持つ方は多いでしょう。理論を理解していても、いざ実装となると最適な書き方がわからないというケースは珍しくありません。
本記事では、Flexboxを使った実践的なレイアウトパターンを解説します。
- ナビゲーションバー(ロゴ + メニュー項目)
- カードレイアウト(等幅・可変幅・ラップ対応)
- Sticky Footer(フッターを最下部に固定)
- メディアオブジェクト(画像 + テキストの横並び)
- 入力フォーム(ラベル + インプット + ボタン)
これらのパターンはWeb開発で頻繁に登場するため、一度習得すれば多くのプロジェクトで活用できます。
前提条件#
本記事を読み進めるにあたり、以下の知識があることを前提としています。
- Flexboxの基本概念(フレックスコンテナとフレックスアイテム)
- 主軸・交差軸と配置プロパティ(
justify-content、align-items)
flex-grow、flex-shrink、flex-basisの役割
これらの基礎知識については、以下の記事で解説しています。
- Flexbox入門 - 柔軟なレイアウトの基本概念を理解する
- Flexboxの配置プロパティ - justify-content・align-items・align-selfの使い方
- flex-grow・flex-shrink・flex-basisを完全理解する
動作確認環境#
- Google Chrome 131以降
- Firefox 133以降
- Safari 18以降
- Microsoft Edge 131以降
パターン1: ナビゲーションバー#
ナビゲーションバーはほぼすべてのWebサイトに存在する基本UIです。Flexboxを使うことで、ロゴとメニュー項目の配置を簡潔に実現できます。
基本構造#
ナビゲーションバーの典型的な構成要素は以下の通りです。
flowchart LR
subgraph nav["ナビゲーションバー"]
logo["ロゴ"]
spacer["余白"]
menu["メニュー項目"]
endパターン1-1: ロゴ左・メニュー右の配置#
最も一般的なナビゲーションパターンです。ロゴを左端に、メニュー項目を右端に配置します。
1
2
3
4
5
6
7
8
9
|
<nav class="navbar">
<a href="/" class="navbar-logo">MyBrand</a>
<ul class="navbar-menu">
<li><a href="/about">About</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background-color: #1a1a2e;
}
.navbar-logo {
font-size: 1.5rem;
font-weight: bold;
color: #ffffff;
text-decoration: none;
}
.navbar-menu {
display: flex;
gap: 2rem;
list-style: none;
margin: 0;
padding: 0;
}
.navbar-menu a {
color: #e0e0e0;
text-decoration: none;
transition: color 0.3s ease;
}
.navbar-menu a:hover {
color: #ffffff;
}
|
justify-content: space-betweenを使用することで、ロゴとメニューの間に自動的に余白が挿入されます。ロゴとメニューがそれぞれ左端と右端に配置され、中間のスペースは均等に分配されます。
パターン1-2: 中央配置のメニュー#
ロゴを左に、メニューを中央に配置するパターンです。
1
2
3
4
5
6
7
8
9
10
11
12
|
<nav class="navbar-centered">
<a href="/" class="navbar-logo">MyBrand</a>
<ul class="navbar-menu">
<li><a href="/about">About</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
<div class="navbar-actions">
<button class="btn-login">Login</button>
</div>
</nav>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
.navbar-centered {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background-color: #1a1a2e;
}
.navbar-logo {
flex: 1;
font-size: 1.5rem;
font-weight: bold;
color: #ffffff;
text-decoration: none;
}
.navbar-menu {
display: flex;
gap: 2rem;
list-style: none;
margin: 0;
padding: 0;
}
.navbar-actions {
flex: 1;
display: flex;
justify-content: flex-end;
}
.btn-login {
padding: 0.5rem 1.5rem;
background-color: #4361ee;
color: #ffffff;
border: none;
border-radius: 4px;
cursor: pointer;
}
|
ロゴと右側のアクションエリアにflex: 1を設定することで、両者が同じ幅を確保します。メニューは自然なコンテンツ幅を維持し、結果としてメニューが中央に配置されます。
パターン1-3: レスポンシブ対応ナビゲーション#
画面幅が狭い場合にハンバーガーメニューへ切り替えるパターンです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
.navbar-responsive {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background-color: #1a1a2e;
}
.navbar-toggle {
display: none;
background: none;
border: none;
color: #ffffff;
font-size: 1.5rem;
cursor: pointer;
}
@media (max-width: 768px) {
.navbar-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
flex-direction: column;
background-color: #1a1a2e;
padding: 1rem;
}
.navbar-menu.active {
display: flex;
}
.navbar-toggle {
display: block;
}
}
|
モバイル表示時にはflex-direction: columnでメニュー項目を縦並びにし、ハンバーガーメニューのトグルで表示・非表示を切り替えます。
パターン2: カードレイアウト#
カードは商品一覧、ブログ記事リスト、チームメンバー紹介など、多くの場面で使用されるUIパターンです。
パターン2-1: 等幅カードの横並び#
すべてのカードを同じ幅で横並びに配置するパターンです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<div class="card-grid">
<article class="card">
<img src="/images/card1.jpg" alt="Card 1" class="card-image">
<div class="card-body">
<h3 class="card-title">カードタイトル1</h3>
<p class="card-text">カードの説明文がここに入ります。</p>
<a href="#" class="card-link">詳しく見る</a>
</div>
</article>
<article class="card">
<img src="/images/card2.jpg" alt="Card 2" class="card-image">
<div class="card-body">
<h3 class="card-title">カードタイトル2</h3>
<p class="card-text">カードの説明文がここに入ります。</p>
<a href="#" class="card-link">詳しく見る</a>
</div>
</article>
<article class="card">
<img src="/images/card3.jpg" alt="Card 3" class="card-image">
<div class="card-body">
<h3 class="card-title">カードタイトル3</h3>
<p class="card-text">カードの説明文がここに入ります。</p>
<a href="#" class="card-link">詳しく見る</a>
</div>
</article>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
.card-grid {
display: flex;
gap: 1.5rem;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.card-image {
width: 100%;
height: 200px;
object-fit: cover;
}
.card-body {
display: flex;
flex-direction: column;
flex: 1;
padding: 1.5rem;
}
.card-title {
margin: 0 0 0.5rem;
font-size: 1.25rem;
}
.card-text {
flex: 1;
margin: 0 0 1rem;
color: #666666;
}
.card-link {
align-self: flex-start;
color: #4361ee;
text-decoration: none;
font-weight: 500;
}
|
各カードにflex: 1を設定することで、すべてのカードが均等な幅になります。カード内部もflex-direction: columnで縦方向のFlexコンテナとし、card-textにflex: 1を設定することでテキスト量が異なってもリンクの位置が揃います。
パターン2-2: ラップ対応カードレイアウト#
カード数が多い場合に自動的に折り返すパターンです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
.card-grid-wrap {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.card-grid-wrap .card {
flex: 1 1 calc(33.333% - 1rem);
min-width: 280px;
max-width: 400px;
}
@media (max-width: 992px) {
.card-grid-wrap .card {
flex: 1 1 calc(50% - 0.75rem);
}
}
@media (max-width: 576px) {
.card-grid-wrap .card {
flex: 1 1 100%;
max-width: none;
}
}
|
flex-wrap: wrapとflex-basisを組み合わせることで、画面幅に応じてカードが自動的に折り返されます。min-widthを設定することで、カードが極端に狭くなることを防止しています。
パターン2-3: カード内のフッター固定#
カードの高さが異なっても、ボタンを常にカード下部に配置するパターンです。
flowchart TB
subgraph card1["カード1"]
direction TB
img1["画像"]
title1["タイトル"]
text1["長いテキスト..."]
spacer1["余白(flex: 1)"]
btn1["ボタン"]
end
subgraph card2["カード2"]
direction TB
img2["画像"]
title2["タイトル"]
text2["短いテキスト"]
spacer2["余白(flex: 1)"]
btn2["ボタン"]
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<div class="card-footer-fixed">
<article class="card">
<div class="card-body">
<h3 class="card-title">タイトル</h3>
<p class="card-text">この説明文は短いです。</p>
</div>
<div class="card-footer">
<button class="btn-primary">詳細を見る</button>
</div>
</article>
<article class="card">
<div class="card-body">
<h3 class="card-title">タイトル</h3>
<p class="card-text">この説明文は長いです。複数行にわたって表示されます。カードの高さに関係なく、ボタンは常に下部に配置されます。</p>
</div>
<div class="card-footer">
<button class="btn-primary">詳細を見る</button>
</div>
</article>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
.card-footer-fixed {
display: flex;
gap: 1.5rem;
}
.card-footer-fixed .card {
flex: 1;
display: flex;
flex-direction: column;
min-height: 300px;
}
.card-footer-fixed .card-body {
flex: 1;
padding: 1.5rem;
}
.card-footer-fixed .card-footer {
padding: 1rem 1.5rem;
border-top: 1px solid #e0e0e0;
}
.btn-primary {
width: 100%;
padding: 0.75rem;
background-color: #4361ee;
color: #ffffff;
border: none;
border-radius: 4px;
cursor: pointer;
}
|
カードにdisplay: flexとflex-direction: columnを設定し、card-bodyにflex: 1を適用します。これにより、コンテンツ部分が余白を吸収し、フッターは常にカード下部に配置されます。
Sticky Footerは、コンテンツ量が少なくてもフッターを画面最下部に固定するパターンです。
問題の背景#
通常のHTMLでは、コンテンツ量が少ない場合にフッターがページ中央付近に表示されてしまいます。
flowchart TB
subgraph problem["問題のあるレイアウト"]
direction TB
header1["ヘッダー"]
content1["少ないコンテンツ"]
footer1["フッター<br/>(中途半端な位置)"]
empty1["空白"]
end
subgraph solution["Sticky Footerの解決策"]
direction TB
header2["ヘッダー"]
content2["少ないコンテンツ"]
spacer2["余白(flex: 1で拡張)"]
footer2["フッター<br/>(常に最下部)"]
end実装方法#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sticky Footer Example</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="site-header">
<h1>サイトタイトル</h1>
</header>
<main class="site-main">
<p>メインコンテンツがここに入ります。</p>
</main>
<footer class="site-footer">
<p>© 2026 MyBrand. All rights reserved.</p>
</footer>
</body>
</html>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
html, body {
height: 100%;
margin: 0;
}
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.site-header {
padding: 1rem 2rem;
background-color: #1a1a2e;
color: #ffffff;
}
.site-main {
flex: 1;
padding: 2rem;
}
.site-footer {
padding: 1rem 2rem;
background-color: #1a1a2e;
color: #ffffff;
text-align: center;
}
|
bodyをdisplay: flexとflex-direction: columnのFlexコンテナとし、min-height: 100vhでビューポート全体の高さを確保します。main要素にflex: 1を設定することで、コンテンツが少なくてもmainが残りのスペースを埋め、結果としてフッターが最下部に固定されます。
応用: ラッパー要素を使用する場合#
既存のHTML構造を変更できない場合、ラッパー要素を追加する方法もあります。
1
2
3
4
5
6
7
8
9
|
.page-wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-content {
flex: 1;
}
|
パターン4: メディアオブジェクト#
メディアオブジェクトは、画像(アバター、サムネイル)とテキストを横並びに配置するパターンです。コメント欄、ユーザープロフィール、記事リストなどで頻繁に使用されます。
パターン4-1: 基本のメディアオブジェクト#
1
2
3
4
5
6
7
8
|
<div class="media">
<img src="/images/avatar.jpg" alt="Avatar" class="media-image">
<div class="media-body">
<h4 class="media-title">ユーザー名</h4>
<p class="media-text">投稿されたコメントの内容がここに入ります。複数行になっても画像の横に配置されます。</p>
<span class="media-date">2026年1月5日</span>
</div>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
.media {
display: flex;
gap: 1rem;
padding: 1rem;
border-bottom: 1px solid #e0e0e0;
}
.media-image {
flex-shrink: 0;
width: 64px;
height: 64px;
border-radius: 50%;
object-fit: cover;
}
.media-body {
flex: 1;
min-width: 0;
}
.media-title {
margin: 0 0 0.25rem;
font-size: 1rem;
font-weight: 600;
}
.media-text {
margin: 0 0 0.5rem;
color: #333333;
line-height: 1.6;
}
.media-date {
font-size: 0.875rem;
color: #888888;
}
|
画像にflex-shrink: 0を設定することで、画像が縮小されることを防止しています。テキスト部分にはflex: 1を適用して残りのスペースを占有し、min-width: 0でオーバーフロー時の問題を回避しています。
パターン4-2: 画像右配置のメディアオブジェクト#
画像を右側に配置するパターンです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
.media-reverse {
display: flex;
flex-direction: row-reverse;
gap: 1rem;
padding: 1rem;
}
.media-reverse .media-image {
flex-shrink: 0;
width: 64px;
height: 64px;
border-radius: 50%;
object-fit: cover;
}
.media-reverse .media-body {
flex: 1;
min-width: 0;
text-align: right;
}
|
flex-direction: row-reverseを使用することで、HTMLの記述順を変えずに画像を右側に配置できます。
パターン4-3: ネストしたメディアオブジェクト(コメントスレッド)#
コメントへの返信など、メディアオブジェクトをネストするパターンです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<div class="media">
<img src="/images/user1.jpg" alt="User 1" class="media-image">
<div class="media-body">
<h4 class="media-title">ユーザー1</h4>
<p class="media-text">親コメントの内容です。</p>
<div class="media media-nested">
<img src="/images/user2.jpg" alt="User 2" class="media-image">
<div class="media-body">
<h4 class="media-title">ユーザー2</h4>
<p class="media-text">返信コメントの内容です。</p>
</div>
</div>
</div>
</div>
|
1
2
3
4
5
6
7
8
9
10
|
.media-nested {
margin-top: 1rem;
padding-left: 0;
border-bottom: none;
}
.media-nested .media-image {
width: 48px;
height: 48px;
}
|
Flexboxの柔軟性により、メディアオブジェクトをネストしても構造が崩れません。ネストされた要素には少し小さいサイズを適用することで、階層構造を視覚的に表現できます。
パターン5: 入力フォーム#
フォーム要素の配置もFlexboxの得意分野です。ラベル、入力フィールド、ボタンの組み合わせを柔軟にレイアウトできます。
パターン5-1: インライン検索フォーム#
1
2
3
4
|
<form class="search-form">
<input type="text" class="search-input" placeholder="検索キーワード">
<button type="submit" class="search-button">検索</button>
</form>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
.search-form {
display: flex;
max-width: 500px;
}
.search-input {
flex: 1;
padding: 0.75rem 1rem;
border: 2px solid #e0e0e0;
border-right: none;
border-radius: 4px 0 0 4px;
font-size: 1rem;
}
.search-input:focus {
outline: none;
border-color: #4361ee;
}
.search-button {
padding: 0.75rem 1.5rem;
background-color: #4361ee;
color: #ffffff;
border: 2px solid #4361ee;
border-radius: 0 4px 4px 0;
font-size: 1rem;
cursor: pointer;
}
.search-button:hover {
background-color: #3651d4;
}
|
入力フィールドにflex: 1を設定することで、ボタンの幅を固定しつつ入力フィールドが残りのスペースを占有します。
パターン5-2: ラベル付きフォームグループ#
1
2
3
4
5
6
7
8
9
|
<div class="form-group">
<label for="username" class="form-label">ユーザー名</label>
<input type="text" id="username" class="form-control">
</div>
<div class="form-group">
<label for="email" class="form-label">メールアドレス</label>
<input type="email" id="email" class="form-control">
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
.form-group {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
.form-label {
flex: 0 0 120px;
font-weight: 500;
}
.form-control {
flex: 1;
padding: 0.75rem 1rem;
border: 2px solid #e0e0e0;
border-radius: 4px;
font-size: 1rem;
}
.form-control:focus {
outline: none;
border-color: #4361ee;
}
@media (max-width: 576px) {
.form-group {
flex-direction: column;
align-items: stretch;
}
.form-label {
flex: none;
margin-bottom: 0.5rem;
}
}
|
ラベルにflex: 0 0 120pxを設定して固定幅を確保し、入力フィールドにはflex: 1で残りのスペースを割り当てます。モバイル表示ではラベルと入力を縦並びに変更しています。
パターン5-3: アドオン付き入力フィールド#
入力フィールドの前後にアイコンやテキストを付加するパターンです。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<div class="input-group">
<span class="input-addon">https://</span>
<input type="text" class="input-field" placeholder="example.com">
</div>
<div class="input-group">
<span class="input-addon">
<svg viewBox="0 0 24 24" width="20" height="20">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
</span>
<input type="text" class="input-field" placeholder="ユーザー名">
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
.input-group {
display: flex;
max-width: 400px;
}
.input-addon {
display: flex;
align-items: center;
padding: 0 1rem;
background-color: #f5f5f5;
border: 2px solid #e0e0e0;
border-right: none;
border-radius: 4px 0 0 4px;
color: #666666;
}
.input-addon svg {
fill: currentColor;
}
.input-field {
flex: 1;
padding: 0.75rem 1rem;
border: 2px solid #e0e0e0;
border-radius: 0 4px 4px 0;
font-size: 1rem;
}
.input-field:focus {
outline: none;
border-color: #4361ee;
}
|
アドオン部分にdisplay: flexとalign-items: centerを適用することで、アイコンやテキストを垂直方向に中央揃えにしています。
パターン6: 中央揃えレイアウト#
要素を水平・垂直方向に中央揃えする需要は非常に高く、Flexboxはこれを最もシンプルに解決できます。
パターン6-1: 完全中央配置#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
.center-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.center-content {
max-width: 400px;
padding: 2rem;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
|
justify-content: centerで水平方向、align-items: centerで垂直方向の中央揃えを実現します。ログインフォームやモーダルダイアログの配置に最適です。
パターン6-2: ローディングスピナー#
1
2
3
4
|
<div class="loading-container">
<div class="spinner"></div>
<p class="loading-text">読み込み中...</p>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
.loading-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 200px;
gap: 1rem;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #e0e0e0;
border-top-color: #4361ee;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.loading-text {
margin: 0;
color: #666666;
}
|
flex-direction: columnと中央揃えを組み合わせることで、スピナーとテキストを縦並びで中央に配置しています。
パターン7: 等間隔配置#
アイテム間の余白を均等に配置するパターンです。
パターン7-1: アイコン列の等間隔配置#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<div class="icon-bar">
<a href="#" class="icon-item">
<svg viewBox="0 0 24 24" width="24" height="24"><path d="..."/></svg>
</a>
<a href="#" class="icon-item">
<svg viewBox="0 0 24 24" width="24" height="24"><path d="..."/></svg>
</a>
<a href="#" class="icon-item">
<svg viewBox="0 0 24 24" width="24" height="24"><path d="..."/></svg>
</a>
<a href="#" class="icon-item">
<svg viewBox="0 0 24 24" width="24" height="24"><path d="..."/></svg>
</a>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
.icon-bar {
display: flex;
justify-content: space-evenly;
padding: 1rem;
background-color: #f5f5f5;
border-radius: 8px;
}
.icon-item {
display: flex;
justify-content: center;
align-items: center;
width: 48px;
height: 48px;
color: #333333;
border-radius: 50%;
transition: background-color 0.3s ease;
}
.icon-item:hover {
background-color: #e0e0e0;
}
|
justify-content: space-evenlyを使用することで、アイテム間と両端に均等な余白が配置されます。
justify-contentの値の違い#
| 値 |
動作 |
適したケース |
space-between |
両端のアイテムは端に配置、間のアイテムは均等配置 |
ナビゲーション、フッター |
space-around |
各アイテムの両側に均等な余白(端は半分) |
バランスの取れた配置 |
space-evenly |
すべての間隔が完全に均等 |
アイコンバー、ボタングループ |
パターン8: 聖杯レイアウト#
聖杯レイアウト(Holy Grail Layout)は、ヘッダー、フッター、メインコンテンツ、左右のサイドバーで構成される古典的なWebレイアウトです。
1
2
3
4
5
6
7
8
9
|
<div class="holy-grail">
<header class="hg-header">ヘッダー</header>
<div class="hg-body">
<nav class="hg-nav">左サイドバー</nav>
<main class="hg-main">メインコンテンツ</main>
<aside class="hg-aside">右サイドバー</aside>
</div>
<footer class="hg-footer">フッター</footer>
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
.holy-grail {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.hg-header,
.hg-footer {
padding: 1rem 2rem;
background-color: #1a1a2e;
color: #ffffff;
}
.hg-body {
display: flex;
flex: 1;
}
.hg-nav {
flex: 0 0 200px;
padding: 1rem;
background-color: #f0f0f0;
}
.hg-main {
flex: 1;
padding: 1rem;
}
.hg-aside {
flex: 0 0 200px;
padding: 1rem;
background-color: #f0f0f0;
}
@media (max-width: 768px) {
.hg-body {
flex-direction: column;
}
.hg-nav,
.hg-aside {
flex: none;
}
}
|
外側のコンテナはflex-direction: columnで縦並びにし、中央のボディ部分はdisplay: flexで横並びにします。サイドバーには固定幅を、メインコンテンツにはflex: 1を設定することで、メインが残りのスペースを占有します。
よくあるFlexboxの問題と解決策#
実務でFlexboxを使用する際に遭遇しやすい問題とその解決策をまとめます。
問題1: テキストがはみ出す#
長いテキストを持つFlexアイテムがコンテナからはみ出す場合があります。
1
2
3
4
5
6
7
8
9
10
11
|
/* 問題のあるコード */
.flex-item {
flex: 1;
}
/* 解決策 */
.flex-item {
flex: 1;
min-width: 0;
overflow-wrap: break-word;
}
|
Flexアイテムのデフォルトmin-widthはautoで、コンテンツ幅以下に縮小されません。min-width: 0を設定することで、この制約を解除できます。
問題2: 画像のアスペクト比が崩れる#
Flex環境で画像が引き伸ばされる問題です。
1
2
3
4
5
6
7
8
9
10
|
/* 問題のあるコード */
.flex-container img {
flex: 1;
}
/* 解決策 */
.flex-container img {
flex-shrink: 0;
object-fit: cover;
}
|
画像にはflex-shrink: 0を設定して縮小を防ぎ、object-fitでトリミング方法を指定します。
問題3: 最後の行が中央揃えになる#
flex-wrap: wrapとjustify-content: centerを組み合わせると、最後の行のアイテムが中央に配置されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/* 問題のあるコード */
.card-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 1rem;
}
/* 解決策1: 疑似要素で埋める */
.card-grid::after {
content: "";
flex: 1 1 300px;
max-width: 400px;
}
/* 解決策2: justify-content: flex-startに変更 */
.card-grid {
justify-content: flex-start;
}
|
疑似要素を追加して残りのスペースを埋めるか、justify-content: flex-startに変更して左揃えにします。
まとめ#
本記事では、Flexboxを使った実践的なレイアウトパターンを解説しました。
| パターン |
主な用途 |
重要なプロパティ |
| ナビゲーションバー |
ヘッダーUI |
justify-content: space-between |
| カードレイアウト |
商品一覧、記事リスト |
flex: 1、flex-wrap: wrap |
| Sticky Footer |
ページレイアウト |
flex: 1(メイン要素) |
| メディアオブジェクト |
コメント、プロフィール |
flex-shrink: 0(画像) |
| 入力フォーム |
検索バー、フォームグループ |
flex: 1(入力フィールド) |
| 中央揃え |
モーダル、ローディング |
justify-content/align-items: center |
これらのパターンは多くのWebサイトで共通して使用されるため、一度習得すれば様々なプロジェクトで活用できます。実際のコードを書きながら練習し、Flexboxの挙動を体で覚えることをおすすめします。
次のステップとして、より複雑な2次元レイアウトが必要な場合はCSS Gridの学習も検討してください。FlexboxとCSS Gridを適切に使い分けることで、あらゆるレイアウト要件に対応できるようになります。
参考リンク#