Skip to Content
Lecture第5回:CSSレイアウト基礎

第5回:CSSレイアウト基礎

🎯 学習目標

  • Flexboxの基本概念を理解する
  • レスポンシブデザインの重要性を学ぶ
  • メディアクエリを使いこなせるようになる
  • 2カラムレイアウトを実装できる

📚 導入(5分)

従来のレイアウト手法の問題点

従来のCSSレイアウトでは以下の問題がありました:

/* floatを使ったレイアウト(古い手法) */ .container { overflow: hidden; /* clearfixのため */ } .sidebar { float: left; width: 300px; } .main-content { float: right; width: calc(100% - 320px); /* 複雑な計算が必要 */ } /* クリアフィックスが必要 */ .container::after { content: ""; display: table; clear: both; }

問題点

  • 複雑なクリアフィックスが必要
  • 垂直中央揃えが困難
  • レスポンシブ対応が煩雑
  • 等高レイアウトが困難

Flexboxの登場とその利点

Flexbox(Flexible Box Layout)により、これらの問題が解決されました:

/* Flexboxを使ったレイアウト */ .container { display: flex; gap: 20px; } .sidebar { width: 300px; } .main-content { flex: 1; /* 残りスペースを占有 */ }

利点

  • シンプルな記述
  • 自動的な等高レイアウト
  • 簡単な垂直中央揃え
  • 柔軟なレスポンシブ対応

💡 理論学習(30分)

Flexboxの概念(20分)

display: flexの効果

.flex-container { display: flex; }

Flexboxを適用すると:

  1. フレックスコンテナ(親要素)になる
  2. 子要素がフレックスアイテムになる
  3. 主軸(main axis)と交差軸(cross axis)が定義される

主軸と交差軸

flex-direction: row; (デフォルト) ┌─────────────────────────────────┐ │ ←───── 主軸(main axis) ─────→ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ ↑ │ │ A │ │ B │ │ C │ │ │ │ └─────┘ └─────┘ └─────┘ │ │ 交差軸 │ │ │ (cross axis) └─────────────────────────────────┘ ↓ flex-direction: column; ┌─────────────┐ │ │ ↑ │ ┌─────┐ │ │ │ │ A │ │ │ 主軸 │ └─────┘ │ │ (main axis) │ │ │ │ ┌─────┐ │ │ │ │ B │ │ │ │ └─────┘ │ ↓ │ │ └─────────────┘ ← 交差軸 →

コンテナ(親要素)のプロパティ

flex-direction:軸の方向
.container { display: flex; /* 主軸の方向を指定 */ flex-direction: row; /* デフォルト:左から右 */ flex-direction: row-reverse; /* 右から左 */ flex-direction: column; /* 上から下 */ flex-direction: column-reverse; /* 下から上 */ }
justify-content:主軸方向の配置
.container { display: flex; /* 主軸方向の配置 */ justify-content: flex-start; /* 開始点に揃える(デフォルト) */ justify-content: flex-end; /* 終了点に揃える */ justify-content: center; /* 中央に揃える */ justify-content: space-between; /* 両端揃え */ justify-content: space-around; /* 均等配置(両端に半分のスペース) */ justify-content: space-evenly; /* 完全均等配置 */ }
justify-content: space-between; ┌─────────────────────────────────┐ │ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │ │ │A│ │B│ │C│ │D│ │ │ └─┘ └─┘ └─┘ └─┘ │ └─────────────────────────────────┘ justify-content: space-around; ┌─────────────────────────────────┐ │ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │ │ │A│ │B│ │C│ │D│ │ │ └─┘ └─┘ └─┘ └─┘ │ └─────────────────────────────────┘
align-items:交差軸方向の配置
.container { display: flex; height: 200px; /* 高さを指定して効果を確認 */ /* 交差軸方向の配置 */ align-items: stretch; /* 伸縮(デフォルト) */ align-items: flex-start; /* 開始点に揃える */ align-items: flex-end; /* 終了点に揃える */ align-items: center; /* 中央に揃える */ align-items: baseline; /* ベースラインに揃える */ }
flex-wrap:折り返し
.container { display: flex; /* 折り返しの制御 */ flex-wrap: nowrap; /* 折り返さない(デフォルト) */ flex-wrap: wrap; /* 折り返す */ flex-wrap: wrap-reverse; /* 逆方向に折り返す */ }
align-content:複数行の配置(flex-wrap: wrapの場合)
.container { display: flex; flex-wrap: wrap; /* 複数行の配置 */ align-content: flex-start; align-content: center; align-content: space-between; }
gap:アイテム間の余白
.container { display: flex; gap: 20px; /* 全方向 */ gap: 10px 20px; /* 行 列 */ column-gap: 20px; /* 列方向のみ */ row-gap: 10px; /* 行方向のみ */ }

アイテム(子要素)のプロパティ

flex:伸縮の制御
.item { /* flex-grow flex-shrink flex-basisの一括指定 */ flex: 1; /* 1 1 0% */ flex: 0 0 200px; /* 伸縮なし、幅200px固定 */ flex: 2 1 300px; /* 成長比2、縮小比1、ベース300px */ } /* 個別指定 */ .item { flex-grow: 1; /* 余白の分配比率 */ flex-shrink: 1; /* 縮小の比率 */ flex-basis: auto; /* ベースサイズ */ }
align-self:個別の交差軸配置
.item { /* このアイテムだけ個別に配置を変更 */ align-self: flex-start; align-self: center; align-self: flex-end; }
order:表示順序の変更
.item1 { order: 2; } /* 2番目に表示 */ .item2 { order: 1; } /* 1番目に表示 */ .item3 { order: 3; } /* 3番目に表示 */

レスポンシブデザインの基礎(10分)

viewport metaタグの重要性

<meta name="viewport" content="width=device-width, initial-scale=1.0">

この設定により:

  • モバイルでも適切なサイズで表示
  • ズーム機能の制御
  • レスポンシブデザインが正常に動作

相対単位の使い分け

/* 絶対単位(固定サイズ) */ .fixed { width: 300px; /* 常に300ピクセル */ } /* 相対単位(可変サイズ) */ .responsive { width: 50%; /* 親要素の50% */ font-size: 1.2em; /* 親要素のフォントサイズの1.2倍 */ padding: 2rem; /* ルート要素のフォントサイズの2倍 */ height: 50vh; /* ビューポート高さの50% */ width: 80vw; /* ビューポート幅の80% */ }
単位説明使用場面
%親要素を基準幅、高さの比率指定
em親要素のfont-sizeを基準余白、内部要素のサイズ
remルート要素のfont-sizeを基準フォントサイズ、統一的な余白
vwビューポート幅の1%レスポンシブな幅
vhビューポート高さの1%フルスクリーン要素
vminvwとvhの小さい方正方形を保つ要素
vmaxvwとvhの大きい方画面全体を覆う要素

メディアクエリの基本

/* デスクトップファースト */ .container { width: 1200px; /* デスクトップ */ } @media (max-width: 1200px) { .container { width: 100%; /* タブレット以下 */ } } @media (max-width: 768px) { .container { padding: 10px; /* モバイル */ } } /* モバイルファースト(推奨) */ .container { width: 100%; /* モバイル */ padding: 10px; } @media (min-width: 768px) { .container { padding: 20px; /* タブレット以上 */ } } @media (min-width: 1200px) { .container { width: 1200px; /* デスクトップ */ margin: 0 auto; } }

🛠️ 実習(50分)

2カラムレイアウトの作成(45分)

HTML構造

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>2カラムレイアウト</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <header class="site-header"> <div class="header-container"> <h1 class="site-title">My Blog</h1> <nav class="main-nav"> <ul class="nav-list"> <li><a href="#" class="nav-link">ホーム</a></li> <li><a href="#" class="nav-link">記事</a></li> <li><a href="#" class="nav-link">プロフィール</a></li> <li><a href="#" class="nav-link">お問い合わせ</a></li> </ul> </nav> </div> </header> <div class="page-container"> <!-- メインコンテンツ --> <main class="main-content"> <article class="article"> <header class="article-header"> <h2 class="article-title">Flexboxの基本</h2> <time class="article-date">2024年1月29日</time> </header> <div class="article-content"> <p>Flexboxは現代のWebデザインに欠かせないレイアウト技術です。</p> <p>従来のfloatベースのレイアウトと比べて、はるかに柔軟で直感的にレイアウトを作成できます。</p> <h3>Flexboxの主な利点</h3> <ul> <li>簡単な垂直中央揃え</li> <li>等高カラムの自動実現</li> <li>柔軟な要素の配置</li> <li>レスポンシブ対応の簡素化</li> </ul> </div> </article> <article class="article"> <header class="article-header"> <h2 class="article-title">レスポンシブデザインの重要性</h2> <time class="article-date">2024年1月28日</time> </header> <div class="article-content"> <p>モバイルファーストの時代において、レスポンシブデザインは必須の技術です。</p> <p>様々なデバイスサイズに対応することで、すべてのユーザーに最適な体験を提供できます。</p> </div> </article> </main> <!-- サイドバー --> <aside class="sidebar"> <section class="widget"> <h3 class="widget-title">プロフィール</h3> <div class="profile"> <img src="https://via.placeholder.com/80" alt="プロフィール画像" class="profile-image"> <p class="profile-text">Web制作を学習中の初心者です。HTML、CSS、JavaScriptを勉強しています。</p> </div> </section> <section class="widget"> <h3 class="widget-title">最新記事</h3> <ul class="recent-posts"> <li class="recent-post"> <a href="#" class="recent-post-link">Flexboxの基本</a> <time class="recent-post-date">2024/01/29</time> </li> <li class="recent-post"> <a href="#" class="recent-post-link">レスポンシブデザインの重要性</a> <time class="recent-post-date">2024/01/28</time> </li> <li class="recent-post"> <a href="#" class="recent-post-link">CSS Gridの使い方</a> <time class="recent-post-date">2024/01/27</time> </li> </ul> </section> <section class="widget"> <h3 class="widget-title">カテゴリー</h3> <ul class="categories"> <li><a href="#" class="category-link">HTML <span class="count">(5)</span></a></li> <li><a href="#" class="category-link">CSS <span class="count">(8)</span></a></li> <li><a href="#" class="category-link">JavaScript <span class="count">(3)</span></a></li> <li><a href="#" class="category-link">デザイン <span class="count">(2)</span></a></li> </ul> </section> </aside> </div> <footer class="site-footer"> <div class="footer-container"> <p class="copyright">&copy; 2024 My Blog. All rights reserved.</p> </div> </footer> </body> </html>

CSS(css/style.css)

/* ========================================== リセットCSS ========================================== */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Helvetica Neue', Arial, 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif; font-size: 16px; line-height: 1.6; color: #333; background-color: #f5f5f5; } a { color: #007bff; text-decoration: none; } a:hover { text-decoration: underline; } img { max-width: 100%; height: auto; } ul { list-style: none; } /* ========================================== ヘッダー ========================================== */ .site-header { background-color: #ffffff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); position: sticky; top: 0; z-index: 100; } .header-container { max-width: 1200px; margin: 0 auto; padding: 0 20px; display: flex; justify-content: space-between; align-items: center; min-height: 60px; } .site-title { font-size: 24px; font-weight: bold; color: #333; } .nav-list { display: flex; gap: 30px; } .nav-link { color: #666; font-weight: 500; padding: 5px 0; transition: color 0.3s ease; } .nav-link:hover { color: #007bff; text-decoration: none; } /* ========================================== メインレイアウト(Flexbox) ========================================== */ .page-container { max-width: 1200px; margin: 0 auto; padding: 40px 20px; display: flex; gap: 40px; align-items: flex-start; /* 上端揃え */ } /* メインコンテンツ */ .main-content { flex: 1; /* 残りスペースを占有 */ min-width: 0; /* Flexアイテムの縮小を許可 */ } /* サイドバー */ .sidebar { width: 300px; flex-shrink: 0; /* 縮小しない */ } /* ========================================== 記事 ========================================== */ .article { background-color: #ffffff; border-radius: 8px; padding: 30px; margin-bottom: 30px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } .article-header { margin-bottom: 20px; padding-bottom: 15px; border-bottom: 1px solid #eee; } .article-title { font-size: 28px; font-weight: bold; margin-bottom: 10px; color: #333; } .article-date { color: #666; font-size: 14px; } .article-content h3 { font-size: 20px; margin: 20px 0 10px; color: #333; } .article-content ul { list-style: disc inside; margin: 15px 0; padding-left: 20px; } .article-content p { margin-bottom: 15px; } /* ========================================== サイドバー ========================================== */ .widget { background-color: #ffffff; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } .widget-title { font-size: 18px; font-weight: bold; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #007bff; color: #333; } /* プロフィール */ .profile { display: flex; align-items: center; gap: 15px; } .profile-image { width: 60px; height: 60px; border-radius: 50%; object-fit: cover; flex-shrink: 0; } .profile-text { font-size: 14px; line-height: 1.5; } /* 最新記事 */ .recent-posts { display: flex; flex-direction: column; gap: 12px; } .recent-post { padding-bottom: 12px; border-bottom: 1px solid #eee; } .recent-post:last-child { border-bottom: none; padding-bottom: 0; } .recent-post-link { display: block; font-weight: 500; margin-bottom: 5px; } .recent-post-date { font-size: 12px; color: #999; } /* カテゴリー */ .categories { display: flex; flex-direction: column; gap: 8px; } .category-link { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; background-color: #f8f9fa; border-radius: 4px; transition: background-color 0.3s ease; } .category-link:hover { background-color: #e9ecef; text-decoration: none; } .count { font-size: 12px; color: #666; } /* ========================================== フッター ========================================== */ .site-footer { background-color: #333; color: #fff; text-align: center; padding: 20px 0; margin-top: 50px; } .footer-container { max-width: 1200px; margin: 0 auto; padding: 0 20px; } .copyright { font-size: 14px; } /* ========================================== レスポンシブデザイン ========================================== */ /* タブレット */ @media (max-width: 768px) { .header-container { flex-direction: column; padding: 20px; gap: 15px; } .nav-list { gap: 20px; } .page-container { flex-direction: column; gap: 30px; } .sidebar { width: 100%; } .article { padding: 20px; } .article-title { font-size: 24px; } } /* モバイル */ @media (max-width: 480px) { .header-container { padding: 15px; } .site-title { font-size: 20px; } .nav-list { flex-wrap: wrap; justify-content: center; gap: 15px; } .page-container { padding: 20px 15px; } .article { padding: 15px; } .article-title { font-size: 20px; } .profile { flex-direction: column; text-align: center; } .widget { padding: 15px; } } /* 横向きスマホ・小さなタブレット */ @media (max-width: 768px) and (orientation: landscape) { .page-container { flex-direction: row; } .sidebar { width: 250px; } }

レスポンシブデザインのポイント

ブレークポイントの設定

/* 一般的なブレークポイント */ @media (min-width: 576px) { /* Small devices (landscape phones) */ } @media (min-width: 768px) { /* Medium devices (tablets) */ } @media (min-width: 992px) { /* Large devices (desktops) */ } @media (min-width: 1200px) { /* Extra large devices (large desktops) */ } /* カスタムブレークポイント */ @media (max-width: 1023px) { /* タブレット以下 */ } @media (max-width: 767px) { /* スマホ */ } @media (max-width: 479px) { /* 小さなスマホ */ }

Flexboxでレスポンシブ対応

.container { display: flex; flex-wrap: wrap; /* 狭い画面では折り返し */ } .item { flex: 1 1 300px; /* 最小幅300px、それ以上は均等分割 */ } /* モバイルでは縦並び */ @media (max-width: 767px) { .container { flex-direction: column; } .item { flex: none; /* 固定サイズに戻す */ } }

📝 まとめ・質疑応答(5分)

Flexboxの主要概念の確認

✅ チェックリスト

  • display: flexの効果を理解した
  • 主軸と交差軸の概念を理解した
  • justify-contentとalign-itemsを使い分けられる
  • flexプロパティで伸縮を制御できる
  • レスポンシブデザインの重要性を理解した

次回予告:CSS Grid

次回学習する内容:

  • CSS Gridの基本概念
  • グリッドコンテナとグリッドアイテム
  • 複雑なレイアウトの実現
  • FlexboxとGridの使い分け

🏠 宿題

  1. カードレイアウトの作成

    .card-container { display: flex; flex-wrap: wrap; gap: 20px; } .card { flex: 1 1 300px; /* レスポンシブカード */ min-height: 200px; }
  2. ナビゲーションメニューの改良

    • ハンバーガーメニューの実装(CSS のみ)
    • スマホ版の縦並びレイアウト
  3. 発展課題:Holy Grail Layout

    .page { display: flex; flex-direction: column; min-height: 100vh; } .content { display: flex; flex: 1; } .main { flex: 1; } .sidebar1 { width: 200px; order: -1; } .sidebar2 { width: 200px; }

📚 参考リソース


次回もお楽しみに! 📱

Last updated on