メインコンテンツ
ここにメインの内容が入ります。サイドバーの幅は固定で、メインコンテンツが残りのスペースを占める構成です。
2025/6/11
このサイトはアフィリエイト広告を利用しています。
「CSSでレイアウトを組もうとすると、いつも思うようにいかない…」 「Flexboxは聞いたことがあるけど、実際どう使えばいいかわからない…」
CSS Flexboxは、従来のfloatやpositionを使った複雑なレイアウト手法に比べて、直感的で柔軟なレイアウトシステムです。一度理解すれば、レスポンシブデザインから複雑なレイアウトまで、効率的に実装できるようになります。
この記事では、Flexboxの基本概念から実践的な活用法まで、図解と実例コードで詳しく解説します。
記事の情報について
本記事は2025年6月時点の情報に基づいています。CSS Flexboxの仕様は安定していますが、最新のブラウザサポート状況についてはMDN Web Docsでご確認ください。
Flexboxは***親要素(フレックスコンテナ)と子要素(フレックスアイテム)***の関係で構成されます。
flowchart TD A[Flexコンテナ<br/>display: flex] --> B[フレックスアイテム1] A --> C[フレックスアイテム2] A --> D[フレックスアイテム3] E[主軸 - Main Axis] --> F[flex-direction で決定] G[交差軸 - Cross Axis] --> H[主軸に垂直な軸]
Flexboxの基本構造と軸の概念
フレックスコンテナ(親要素)のプロパティ:
プロパティ | 機能 | 主な値 |
---|---|---|
display | Flexbox有効化 | flex , inline-flex |
flex-direction | 配置方向 | row , column , row-reverse |
justify-content | 主軸方向の配置 | flex-start , center , space-between |
align-items | 交差軸方向の配置 | stretch , center , flex-start |
flex-wrap | 折り返し制御 | nowrap , wrap , wrap-reverse |
フレックスアイテム(子要素)のプロパティ:
プロパティ | 機能 | 使用例 |
---|---|---|
flex-grow | 拡張比率 | 0 (拡張しない), 1 (等分) |
flex-shrink | 縮小比率 | 1 (縮小する), 0 (縮小しない) |
flex-basis | 基本サイズ | auto , 100px , 30% |
align-self | 個別の交差軸配置 | auto , center , flex-end |
学習のコツ
Flexboxの理解には実際にコードを書いて動作を確認することが重要です。ブラウザの開発者ツールでプロパティの値を変更しながら、視覚的に確認することをおすすめします。
<nav class="navigation"> <div class="nav-brand">ロゴ</div> <ul class="nav-menu"> <li><a href="#home">ホーム</a></li> <li><a href="#about">概要</a></li> <li><a href="#services">サービス</a></li> <li><a href="#contact">お問い合わせ</a></li> </ul></nav>
.navigation {display: flex;justify-content: space-between;align-items: center;padding: 1rem 2rem;background-color: #333;color: white;}
.nav-brand {font-size: 1.5rem;font-weight: bold;}
.nav-menu {display: flex;list-style: none;margin: 0;padding: 0;gap: 2rem;}
.nav-menu a {color: white;text-decoration: none;transition: color 0.3s;}
.nav-menu a:hover {color: #007bff;}
レスポンシブ対応版:
@media (max-width: 768px) {.navigation {flex-direction: column;gap: 1rem;}
.nav-menu {flex-direction: column;text-align: center;gap: 1rem;}}
サービスの説明文がここに入ります。詳細な内容を記載します。
サービスの説明文がここに入ります。詳細な内容を記載します。
サービスの説明文がここに入ります。詳細な内容を記載します。
<div class="card-container"> <div class="card"> <img src="image1.jpg" alt="サービス1"> <div class="card-content"> <h3>サービス1</h3> <p>サービスの説明文がここに入ります。詳細な内容を記載します。</p> <button class="card-button">詳細を見る</button> </div></div>
<div class="card"> <img src="image2.jpg" alt="サービス2"> <div class="card-content"> <h3>サービス2</h3> <p>サービスの説明文がここに入ります。詳細な内容を記載します。</p> <button class="card-button">詳細を見る</button> </div></div>
<div class="card"> <img src="image3.jpg" alt="サービス3"> <div class="card-content"> <h3>サービス3</h3> <p>サービスの説明文がここに入ります。詳細な内容を記載します。</p> <button class="card-button">詳細を見る</button> </div></div></div>
.card-container {display: flex;gap: 2rem;padding: 2rem;flex-wrap: wrap;}
.card {flex: 1;min-width: 300px;background: white;border-radius: 8px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);overflow: hidden;transition: transform 0.3s ease;}
.card:hover {transform: translateY(-5px);}
.card img {width: 100%;height: 200px;object-fit: cover;}
.card-content {padding: 1.5rem;display: flex;flex-direction: column;gap: 1rem;}
.card-content h3 {margin: 0;color: #333;}
.card-content p {margin: 0;color: #666;line-height: 1.6;}
.card-button {padding: 0.75rem 1.5rem;background-color: #007bff;color: white;border: none;border-radius: 4px;cursor: pointer;transition: background-color 0.3s;align-self: flex-start;}
.card-button:hover {background-color: #0056b3;}
@media (max-width: 992px) {.card {flex: 1 1 calc(50% - 1rem); /* 2列表示 */}}
@media (max-width: 576px) {.card {flex: 1 1 100%; /* 1列表示 */min-width: unset;}
.card-container {gap: 1rem;padding: 1rem;}}
flex プロパティの使い分け
flex: 1
- 等分に拡張flex: 0 0 300px
- 300px固定サイズflex: 1 1 calc(33.333% - 1rem)
- 3列等分(gap考慮)この内容は垂直・水平の中央に配置されます。
基本的な中央配置:
<div class="center-container"> <div class="center-content"> <h2>中央配置されたコンテンツ</h2> <p>この内容は垂直・水平の中央に配置されます。</p> </div></div>
.center-container {display: flex;justify-content: center;align-items: center;min-height: 100vh;background-color: #f5f5f5;}
.center-content {text-align: center;background: white;padding: 3rem;border-radius: 8px;box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);max-width: 500px;}
複数要素の中央配置:
.multi-center {display: flex;flex-direction: column;justify-content: center;align-items: center;gap: 2rem;min-height: 100vh;}
.multi-center .item {padding: 1rem 2rem;background-color: #007bff;color: white;border-radius: 4px;}
ここにメインの内容が入ります。サイドバーの幅は固定で、メインコンテンツが残りのスペースを占める構成です。
<div class="layout-container"> <aside class="sidebar"> <h3>サイドバー</h3> <nav> <ul> <li><a href="#section1">セクション1</a></li> <li><a href="#section2">セクション2</a></li> <li><a href="#section3">セクション3</a></li> </ul> </nav> </aside> <main class="main-content"> <h1>メインコンテンツ</h1> <p>ここにメインの内容が入ります。サイドバーの幅は固定で、メインコンテンツが残りのスペースを占める構成です。</p> </main></div>
.layout-container {display: flex;min-height: 100vh;gap: 2rem;}
.sidebar {flex: 0 0 250px; /* 250px固定幅 */background-color: #f8f9fa;padding: 2rem;border-right: 1px solid #e9ecef;}
.sidebar h3 {margin-top: 0;color: #333;}
.sidebar ul {list-style: none;padding: 0;}
.sidebar li {margin-bottom: 0.5rem;}
.sidebar a {color: #007bff;text-decoration: none;}
.sidebar a:hover {text-decoration: underline;}
.main-content {flex: 1; /* 残りのスペースを占める */padding: 2rem;}
/* レスポンシブ対応 */@media (max-width: 768px) {.layout-container {flex-direction: column;}
.sidebar {flex: none;border-right: none;border-bottom: 1px solid #e9ecef;}}
<div class="page-container"> <header class="header"> <h1>ヘッダー</h1> </header> <main class="main"> <p>メインコンテンツ。コンテンツが少なくても、フッターは画面下部に固定されます。</p> </main> <footer class="footer"> <p>© 2025 サイト名. All rights reserved.</p> </footer></div>
.page-container {display: flex;flex-direction: column;min-height: 100vh;}
.header {background-color: #333;color: white;padding: 1rem 2rem;}
.main {flex: 1; /* 残りのスペースを全て占める */padding: 2rem;}
.footer {background-color: #f8f9fa;padding: 1rem 2rem;text-align: center;border-top: 1px solid #e9ecef;}
Sticky Footerの重要性
コンテンツが少ないページでも、フッターが画面下部に固定されることで、プロフェッショナルな印象を与えることができます。特にシングルページアプリケーションでは必須のレイアウトパターンです。
<form class="form-container"> <div class="form-group"> <label for="name">お名前</label> <input type="text" id="name" name="name" required> </div> <div class="form-group"> <label for="email">メールアドレス</label> <input type="email" id="email" name="email" required> </div> <div class="form-group"> <label for="message">メッセージ</label> <textarea id="message" name="message" rows="5" required></textarea> </div> <div class="form-actions"> <button type="submit">送信</button> <button type="reset">リセット</button> </div></form>
.form-container {max-width: 600px;margin: 0 auto;padding: 2rem;background: white;border-radius: 8px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);}
.form-group {display: flex;flex-direction: column;margin-bottom: 1.5rem;}
.form-group label {margin-bottom: 0.5rem;font-weight: bold;color: #333;}
.form-group input,.form-group textarea {padding: 0.75rem;border: 1px solid #ddd;border-radius: 4px;font-size: 1rem;transition: border-color 0.3s;}
.form-group input:focus,.form-group textarea:focus {outline: none;border-color: #007bff;}
.form-actions {display: flex;gap: 1rem;justify-content: flex-end;}
.form-actions button {padding: 0.75rem 2rem;border: none;border-radius: 4px;cursor: pointer;font-size: 1rem;transition: background-color 0.3s;}
.form-actions button[type="submit"] {background-color: #007bff;color: white;}
.form-actions button[type="submit"]:hover {background-color: #0056b3;}
.form-actions button[type="reset"] {background-color: #6c757d;color: white;}
.form-actions button[type="reset"]:hover {background-color: #545b62;}
<div class="gallery"> <div class="gallery-item"> <img src="image1.jpg" alt="画像1"> <div class="gallery-overlay"> <h3>タイトル1</h3> </div></div>
<div class="gallery-item"> <img src="image2.jpg" alt="画像2"> <div class="gallery-overlay"> <h3>タイトル2</h3> </div></div>
<div class="gallery-item"> <img src="image3.jpg" alt="画像3"> <div class="gallery-overlay"> <h3>タイトル3</h3> </div></div><!-- 他の画像アイテム --></div>
.gallery {display: flex;flex-wrap: wrap;gap: 1rem;padding: 2rem;}
.gallery-item {flex: 1 1 calc(33.333% - 1rem);min-width: 250px;position: relative;aspect-ratio: 1 / 1;overflow: hidden;border-radius: 8px;cursor: pointer;}
.gallery-item img {width: 100%;height: 100%;object-fit: cover;transition: transform 0.3s ease;}
.gallery-item:hover img {transform: scale(1.1);}
.gallery-overlay {position: absolute;bottom: 0;left: 0;right: 0;background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));color: white;padding: 2rem 1rem 1rem;transform: translateY(100%);transition: transform 0.3s ease;}
.gallery-item:hover .gallery-overlay {transform: translateY(0);}
.gallery-overlay h3 {margin: 0;font-size: 1.2rem;}
/* レスポンシブ対応 */@media (max-width: 768px) {.gallery-item {flex: 1 1 calc(50% - 0.5rem);min-width: unset;}}
@media (max-width: 480px) {.gallery-item {flex: 1 1 100%;}
.gallery {gap: 0.5rem;padding: 1rem;}}
<div class="pricing-container"> <div class="pricing-card"> <div class="pricing-header"> <h3>ベーシック</h3> <div class="price">¥1,000<span>/月</span></div> </div> <ul class="pricing-features"> <li>機能1</li> <li>機能2</li> <li>サポート: メール</li> </ul> <button class="pricing-button">選択する</button> </div>
<div class="pricing-card featured"> <div class="pricing-badge">おすすめ</div> <div class="pricing-header"> <h3>スタンダード</h3> <div class="price">¥2,000<span>/月</span></div> </div> <ul class="pricing-features"> <li>機能1</li> <li>機能2</li> <li>機能3</li> <li>サポート: 電話・メール</li> </ul> <button class="pricing-button">選択する</button> </div>
<div class="pricing-card"> <div class="pricing-header"> <h3>プレミアム</h3> <div class="price">¥3,000<span>/月</span></div> </div> <ul class="pricing-features"> <li>全機能利用可能</li> <li>優先サポート</li> <li>カスタマイズ対応</li> </ul> <button class="pricing-button">選択する</button> </div></div>
.pricing-container {display: flex;gap: 2rem;padding: 2rem;justify-content: center;flex-wrap: wrap;}
.pricing-card {flex: 1;max-width: 300px;background: white;border: 2px solid #e9ecef;border-radius: 12px;padding: 2rem;text-align: center;position: relative;transition: transform 0.3s ease, box-shadow 0.3s ease;}
.pricing-card:hover {transform: translateY(-5px);box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);}
.pricing-card.featured {border-color: #007bff;transform: scale(1.05);}
.pricing-badge {position: absolute;top: -12px;left: 50%;transform: translateX(-50%);background-color: #007bff;color: white;padding: 0.5rem 1rem;border-radius: 20px;font-size: 0.875rem;font-weight: bold;}
.pricing-header h3 {margin: 0 0 1rem 0;color: #333;font-size: 1.5rem;}
.price {font-size: 2.5rem;font-weight: bold;color: #007bff;margin-bottom: 2rem;}
.price span {font-size: 1rem;color: #666;font-weight: normal;}
.pricing-features {list-style: none;padding: 0;margin: 0 0 2rem 0;}
.pricing-features li {padding: 0.75rem 0;border-bottom: 1px solid #f1f1f1;color: #555;}
.pricing-features li:last-child {border-bottom: none;}
.pricing-button {width: 100%;padding: 1rem;background-color: #007bff;color: white;border: none;border-radius: 6px;font-size: 1rem;font-weight: bold;cursor: pointer;transition: background-color 0.3s ease;}
.pricing-button:hover {background-color: #0056b3;}
.featured .pricing-button {background-color: #28a745;}
.featured .pricing-button:hover {background-color: #1e7e34;}
<nav class="breadcrumb"> <a href="/">ホーム</a> <span class="separator">/</span> <a href="/category">カテゴリ</a> <span class="separator">/</span> <a href="/category/subcategory">サブカテゴリ</a> <span class="separator">/</span> <span class="current">現在のページ</span></nav>
.breadcrumb {display: flex;align-items: center;padding: 1rem 2rem;background-color: #f8f9fa;border-bottom: 1px solid #e9ecef;font-size: 0.875rem;flex-wrap: wrap;gap: 0.5rem;}
.breadcrumb a {color: #007bff;text-decoration: none;transition: color 0.3s ease;}
.breadcrumb a:hover {color: #0056b3;text-decoration: underline;}
.separator {color: #6c757d;margin: 0 0.25rem;}
.current {color: #495057;font-weight: 500;}
/* レスポンシブ対応 */@media (max-width: 576px) {.breadcrumb {padding: 0.75rem 1rem;font-size: 0.75rem;}}
<div class="alert success"> <div class="alert-content"> <span class="alert-icon">✓</span> <div class="alert-text"> <strong>成功!</strong> データが正常に保存されました。 </div></div><button class="alert-close">×</button></div>
<div class="alert warning"> <div class="alert-content"> <span class="alert-icon">⚠</span> <div class="alert-text"> <strong>注意!</strong> この操作は元に戻せません。 </div></div><button class="alert-close">×</button></div>
<div class="alert error"> <div class="alert-content"> <span class="alert-icon">✕</span> <div class="alert-text"> <strong>エラー!</strong> 入力内容に問題があります。 </div></div><button class="alert-close">×</button></div>
.alert {display: flex;align-items: center;justify-content: space-between;padding: 1rem 1.5rem;margin-bottom: 1rem;border-radius: 6px;border-left: 4px solid;}
.alert-content {display: flex;align-items: center;gap: 0.75rem;}
.alert-icon {font-size: 1.25rem;font-weight: bold;}
.alert-text {line-height: 1.4;}
.alert-close {background: none;border: none;font-size: 1.5rem;cursor: pointer;opacity: 0.7;transition: opacity 0.3s ease;padding: 0;width: 2rem;height: 2rem;display: flex;align-items: center;justify-content: center;}
.alert-close:hover {opacity: 1;}
/* アラートタイプ別のスタイル */.alert.success {background-color: #d4edda;border-left-color: #28a745;color: #155724;}
.alert.warning {background-color: #fff3cd;border-left-color: #ffc107;color: #856404;}
.alert.error {background-color: #f8d7da;border-left-color: #dc3545;color: #721c24;}
/* レスポンシブ対応 */@media (max-width: 576px) {.alert {flex-direction: column;align-items: flex-start;gap: 1rem;}
.alert-close {align-self: flex-end;margin-top: -0.5rem;}}
問題:
.container {display: flex;justify-content: center; /* 効かない */}
.item {width: 100px;height: 100px;}
原因と解決法:
flowchart TD A[justify-content が効かない] --> B[原因を特定] B --> C[フレックスアイテムのサイズ確認] B --> D[flex-direction の確認] B --> E[親要素の幅確認] C --> F[width/heightが固定されている] D --> G[columnの場合はalign-itemsを使用] E --> H[親要素の幅が不足]
配置問題の診断フロー
修正例:
.container {display: flex;justify-content: center;width: 100%; /* 親要素の幅を確保 */}
/* または */.container {display: flex;flex-direction: column;align-items: center; /* 縦方向の場合 */}
問題:
.sidebar {width: 250px; /* 指定したのに縮む */}
解決法:
.sidebar {flex: 0 0 250px; /* 縮小させない *//* または */min-width: 250px;flex-shrink: 0;}
問題: カード要素の高さがバラバラになる
解決法:
.card-container {display: flex;align-items: stretch; /* デフォルト値だが明示 */}
.card {display: flex;flex-direction: column;}
.card-content {flex: 1; /* 残りスペースを占める */}
よくある落とし穴
align-items: stretch
はデフォルト値ですが、子要素に固定の高さがあると無効になりますflex-wrap: wrap
を使用する場合、各行で独立して配置されることに注意効率的なFlexbox使用法:
/* 推奨しない */.container {display: flex;flex-wrap: wrap; /* 必要ない場合は指定しない */}
/* 推奨 */.container {display: flex; /* wrapが不要なら指定しない */}
/* 曖昧 */.item {flex: 1;}
/* 明確 */.item {flex: 1 0 auto; /* 拡張、縮小、ベースサイズを明示 */}
/* 動的な変更が多い場合 */.dynamic-item {flex-basis: auto; /* contentベースのサイズ */will-change: transform; /* アニメーション予告 */}
ブラウザ | サポート状況 | 注意点 |
---|---|---|
Chrome 29+ | 完全サポート | - |
Firefox 28+ | 完全サポート | - |
Safari 9+ | 完全サポート | 古いバージョンで一部制限 |
Edge | 完全サポート | - |
IE 11 | 部分サポート | 古い仕様の実装 |
/* フォールバック付きの実装例 */.fallback-flex {display: table; /* IE8-9対応 */display: flex; /* モダンブラウザ */width: 100%;}
.fallback-item {display: table-cell; /* IE8-9対応 */flex: 1; /* モダンブラウザ */vertical-align: top;}
/* 機能検出を使った分岐 */@supports (display: flex) {.modern-layout {display: flex;justify-content: space-between;}}
@supports not (display: flex) {.modern-layout {/* floatやinline-blockでの代替実装 */display: table;width: 100%;}}
CSS FlexboxはモダンなWebレイアウトの基盤技術として、フロントエンド開発には欠かせないスキルです。
Flexboxをマスターすることで、思い通りのレイアウトを迅速に実装できるようになります。今回紹介した実例コードを参考に、実際のプロジェクトで活用してみてください。
継続学習のために
CSS技術は日々進化しています。Flexboxの基礎を固めた後は、CSS GridやContainer Queriesなどの新しい技術も学習し、より豊かな表現力を身につけていきましょう。