跳轉到

RWD 網頁

開始之前

任務目標

在這個章節中,我們會完成:

  • 了解 RWD 網頁設計的概念與重要性
  • 深入理解 Bootstrap Grid 系統
  • 優化文章列表與詳細頁面的響應式設計
  • 學習響應式設計的測試方法

什麼是 RWD?

RWD (Responsive Web Design,響應式網頁設計) 是一種網頁設計方法,讓網站能夠自動適應不同裝置的螢幕尺寸和解析度。

為什麼需要 RWD?

原因 說明
多裝置時代 使用者可能用手機、平板、電腦瀏覽網站
提升使用體驗 不需要縮放或左右滑動就能閱讀內容
SEO 優化 Google 偏好響應式網站
維護成本低 不需要維護多個版本的網站
提高轉換率 好的行動體驗能提高使用者停留時間

RWD 的三大核心技術

1. Fluid Grid(流動格線)

使用百分比而非固定像素來定義寬度:

/* 傳統固定寬度 */
.container {
  width: 960px;
}

/* 響應式流動寬度 */
.container {
  width: 100%;
  max-width: 1200px;
}

2. Flexible Images(彈性圖片)

讓圖片能根據容器大小縮放:

img {
  max-width: 100%;
  height: auto;
}

3. Media Queries(媒體查詢)

根據螢幕尺寸套用不同的 CSS 樣式:

/* 小螢幕 */
@media (max-width: 767px) {
  .sidebar {
    display: none;
  }
}

/* 大螢幕 */
@media (min-width: 768px) {
  .sidebar {
    display: block;
  }
}

Viewport 設定

要讓 RWD 正常運作,必須在 HTML 的 <head> 中加入 viewport meta tag:

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

這行設定告訴瀏覽器:

  • width=device-width: 網頁寬度等於裝置寬度
  • initial-scale=1.0: 初始縮放比例為 1:1

我們在 templates/base.html 中已經加入了這個設定。

Bootstrap Grid 系統

Bootstrap 使用 12 欄位格線系統 來實現響應式佈局,這是 Bootstrap 最強大的功能之一。

Grid 基本結構

<div class="container">  <!-- (1)! -->
  <div class="row">  <!-- (2)! -->
    <div class="col-md-6">欄位 1</div>  <!-- (3)! -->
    <div class="col-md-6">欄位 2</div>
  </div>
</div>
  1. 容器: 固定寬度(container) 或 全寬(container-fluid)
  2. 列: 包含欄位的橫排
  3. 欄位: 內容區塊,總和為 12

斷點 (Breakpoints)

Bootstrap 5 定義了六個響應式斷點:

斷點 Class 前綴 螢幕寬度 裝置類型
Extra small (無) <576px 手機 (直向)
Small sm ≥576px 手機 (橫向)
Medium md ≥768px 平板
Large lg ≥992px 桌機
Extra large xl ≥1200px 大桌機
Extra extra large xxl ≥1400px 超大桌機

Grid 使用範例

相同寬度欄位

<div class="row">
  <div class="col">欄位 1</div>
  <div class="col">欄位 2</div>
  <div class="col">欄位 3</div>
</div>

三個欄位會自動平分空間(各佔 4 欄)。

指定欄位寬度

<div class="row">
  <div class="col-8">主要內容 (8/12)</div>
  <div class="col-4">側邊欄 (4/12)</div>
</div>

響應式欄位

<div class="row">
  <div class="col-12 col-md-6 col-lg-4">
    <!-- 手機: 12 欄 (全寬)
         平板: 6 欄 (半寬)
         桌機: 4 欄 (三分之一) -->
  </div>
</div>

Grid Class 命名規則

col-{breakpoint}-{columns}

  • col-12: 所有尺寸都佔 12 欄(全寬)
  • col-md-6: 中等螢幕以上佔 6 欄
  • col-lg-4: 大螢幕以上佔 4 欄

沒有指定的斷點會使用較小斷點的設定。

實際體驗 Grid 系統

讓我們建立一個完整的 HTML 檔案,直接在瀏覽器中體驗 Bootstrap Grid 的響應式效果:

grid_demo.html
<!DOCTYPE html>
<html lang="zh-Hant">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Bootstrap Grid 系統展示" />
    <meta name="keywords" content="Bootstrap, Grid, RWD" />
    <title>Bootstrap Grid 系統展示</title>
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          rel="stylesheet" />
    <style>
      .demo-box {
        background-color: #0d6efd;
        color: white;
        padding: 20px;
        margin-bottom: 15px;
        border-radius: 5px;
        text-align: center;
        font-weight: bold;
      }
      .demo-box-secondary {
        background-color: #6c757d;
      }
      .demo-box-success {
        background-color: #198754;
      }
      .demo-box-warning {
        background-color: #ffc107;
        color: #000;
      }
    </style>
  </head>
  <body>
    <div class="container my-5">
      <h1 class="text-center mb-5">
        Bootstrap Grid 系統展示
      </h1>
      <p class="text-center text-muted mb-4">
        試著調整瀏覽器視窗大小,觀察欄位如何自動調整!
      </p>

      <!-- 範例 1: 相同寬度 -->
      <h2 class="mb-3">
        範例 1: 自動平分欄位
      </h2>
      <div class="row mb-5">
        <div class="col">
          <div class="demo-box">
            欄位 1
          </div>
        </div>
        <div class="col">
          <div class="demo-box demo-box-secondary">
            欄位 2
          </div>
        </div>
        <div class="col">
          <div class="demo-box demo-box-success">
            欄位 3
          </div>
        </div>
      </div>

      <!-- 範例 2: 固定欄位寬度 -->
      <h2 class="mb-3">
        範例 2: 主內容 + 側邊欄 (8:4)
      </h2>
      <div class="row mb-5">
        <div class="col-8">
          <div class="demo-box">
            主要內容 (8/12)
          </div>
        </div>
        <div class="col-4">
          <div class="demo-box demo-box-secondary">
            側邊欄 (4/12)
          </div>
        </div>
      </div>

      <!-- 範例 3: 響應式欄位 -->
      <h2 class="mb-3">
        範例 3: 響應式卡片網格
      </h2>
      <p class="text-muted">
        手機: 1 欄 | 平板: 2 欄 | 桌機: 4 欄
      </p>
      <div class="row mb-5">
        <div class="col-12 col-md-6 col-lg-3">
          <div class="demo-box">
            卡片 1
          </div>
        </div>
        <div class="col-12 col-md-6 col-lg-3">
          <div class="demo-box demo-box-secondary">
            卡片 2
          </div>
        </div>
        <div class="col-12 col-md-6 col-lg-3">
          <div class="demo-box demo-box-success">
            卡片 3
          </div>
        </div>
        <div class="col-12 col-md-6 col-lg-3">
          <div class="demo-box demo-box-warning">
            卡片 4
          </div>
        </div>
      </div>

      <!-- 範例 4: 文章卡片佈局 -->
      <h2 class="mb-3">
        範例 4: 文章列表佈局
      </h2>
      <p class="text-muted">
        手機: 1 欄 | 小螢幕: 2 欄 | 桌機: 3 欄 | 大螨幕: 4 欄
      </p>
      <div class="row mb-5">
        <div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-3">
          <div class="card">
            <div class="card-body">
              <h5 class="card-title">
                文章標題 1
              </h5>
              <p class="card-text">
                這是文章的簡短描述內容...
              </p>
              <a href="#" class="btn btn-primary btn-sm">閱讀更多</a>
            </div>
          </div>
        </div>
        <div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-3">
          <div class="card">
            <div class="card-body">
              <h5 class="card-title">
                文章標題 2
              </h5>
              <p class="card-text">
                這是文章的簡短描述內容...
              </p>
              <a href="#" class="btn btn-primary btn-sm">閱讀更多</a>
            </div>
          </div>
        </div>
        <div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-3">
          <div class="card">
            <div class="card-body">
              <h5 class="card-title">
                文章標題 3
              </h5>
              <p class="card-text">
                這是文章的簡短描述內容...
              </p>
              <a href="#" class="btn btn-primary btn-sm">閱讀更多</a>
            </div>
          </div>
        </div>
        <div class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-3">
          <div class="card">
            <div class="card-body">
              <h5 class="card-title">
                文章標題 4
              </h5>
              <p class="card-text">
                這是文章的簡短描述內容...
              </p>
              <a href="#" class="btn btn-primary btn-sm">閱讀更多</a>
            </div>
          </div>
        </div>
      </div>

      <!-- 目前螢幕尺寸指示器 -->
      <div class="alert alert-info text-center">
        <strong>目前螢幕尺寸:</strong>
        <span class="d-inline d-sm-none">Extra Small (&lt;576px)</span>
        <span class="d-none d-sm-inline d-md-none">Small (≥576px)</span>
        <span class="d-none d-md-inline d-lg-none">Medium (≥768px)</span>
        <span class="d-none d-lg-inline d-xl-none">Large (≥992px)</span>
        <span class="d-none d-xl-inline d-xxl-none">Extra Large (≥1200px)</span>
        <span class="d-none d-xxl-inline">Extra Extra Large (≥1400px)</span>
      </div>
    </div>

    <!-- Bootstrap JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  </body>
</html>

如何使用這個範例

步驟:

  1. 複製上面的完整程式碼
  2. 建立一個新檔案 grid_demo.html
  3. 貼上程式碼並儲存
  4. 用瀏覽器打開這個檔案
  5. 調整瀏覽器視窗大小,觀察欄位如何自動調整!

你會看到:

  • 視窗寬度改變時,欄位會自動重新排列
  • 底部的指示器會顯示目前的螢幕尺寸
  • 不同範例展示了不同的 Grid 使用方式

這就是 RWD 的威力!一套程式碼,適應所有裝置。

優化文章卡片元件

讓我們進一步優化 article_card.html,加入更多響應式設計:

blog/templates/blog/components/article_card.html
<div class="col-12 col-sm-6 col-md-6 col-lg-4 col-xl-3 mb-4">  <!-- (1)! -->
  <div class="card h-100">
    <div class="card-body d-flex flex-column">  <!-- (2)! -->
      <h5 class="card-title">
        {{ article.title }}
      </h5>
      <h6 class="card-subtitle mb-2 text-muted">
        {{ article.author.name }}
      </h6>
      <p class="card-text flex-grow-1">  <!-- (3)! -->
        {{ article.content|truncatewords:30 }}
      </p>
    </div>
    <div class="card-footer bg-transparent">
      <div class="d-flex justify-content-between align-items-center">  <!-- (4)! -->
        <small class="text-muted">
          {{ article.created_at|date:"Y-m-d" }}  <!-- (5)! -->
        </small>
        <a href="{% url 'article_detail' article.id %}"
           class="btn btn-primary btn-sm">
          閱讀更多
        </a>
      </div>
    </div>
  </div>
</div>
  1. 響應式欄位設定: 手機 1 欄、小螢幕 2 欄、中螢幕 2 欄、大螢幕 3 欄、超大螢幕 4 欄
  2. 使用 Flexbox 垂直排列卡片內容
  3. 內容區塊自動擴展 (flex-grow-1),推送按鈕到底部
  4. 使用 Flexbox 水平排列頁尾元素
  5. 在小螢幕上只顯示日期,不顯示時間

響應式佈局說明

不同螢幕尺寸的顯示效果:

螢幕尺寸 每列卡片數 欄位設定 裝置類型
Extra small (<576px) 1 欄 col-12 手機直向
Small (≥576px) 2 欄 col-sm-6 手機橫向
Medium (≥768px) 2 欄 col-md-6 平板
Large (≥992px) 3 欄 col-lg-4 桌機
Extra large (≥1200px) 4 欄 col-xl-3 大桌機

這就是 col-12 col-sm-6 col-md-6 col-lg-4 col-xl-3 的完整含義:隨著螢幕變大,每列能容納的卡片數量逐漸增加,提供最佳的閱讀體驗。

優化文章詳細頁

優化 article_detail.html 的響應式設計,加入更多響應式調整:

blog/templates/blog/article_detail.html
{% extends "blog/base.html" %}

{% block title %}
  {{ article.title }} - Django 大冒險
{% endblock title %}

{% block blog_content %}
  <nav aria-label="breadcrumb" class="d-none d-md-block">  <!-- (1)! -->
    <ol class="breadcrumb">
      <li class="breadcrumb-item">
        <a href="{% url 'article_list' %}">文章列表</a>
      </li>
      <li class="breadcrumb-item active">
        {{ article.title }}
      </li>
    </ol>
  </nav>

  <article class="card">
    <div class="card-body">
      <h1 class="card-title fs-3 fs-md-2 fs-lg-1">  <!-- (2)! -->
        {{ article.title }}
      </h1>

      <div class="d-flex flex-column flex-md-row align-items-md-center mb-3 text-muted">  <!-- (3)! -->
        <span class="me-md-3 mb-2 mb-md-0">  <!-- (4)! -->
          <i class="bi bi-person"></i>
          作者:{{ article.author.name }}
        </span>
        <span>
          <i class="bi bi-calendar"></i>
          發布時間:{{ article.created_at|date:"Y-m-d H:i" }}
        </span>
      </div>

      {% if article.tags.exists %}
        <div class="mb-3">
          {% for tag in article.tags.all %}
            <span class="badge bg-secondary me-1 mb-1">{{ tag.name }}</span>  <!-- (5)! -->
          {% endfor %}
        </div>
      {% endif %}

      <hr />

      <div class="article-content fs-6 fs-md-5">  <!-- (6)! -->
        {{ article.content|linebreaks }}
      </div>
    </div>

    <div class="card-footer bg-light">
      <div class="d-flex justify-content-between align-items-center">
        <a href="{% url 'article_list' %}"
           class="btn btn-outline-secondary btn-sm">
          <span class="d-none d-sm-inline">  <!-- (7)! -->
            <i class="bi bi-arrow-left"></i> 返回列表
          </span>
          <span class="d-inline d-sm-none">  <!-- (8)! -->
            <i class="bi bi-arrow-left"></i>
          </span>
        </a>
        <small class="text-muted d-none d-md-inline">  <!-- (9)! -->
          最後更新:{{ article.updated_at|date:"Y-m-d" }}
        </small>
      </div>
    </div>
  </article>
{% endblock blog_content %}
  1. 麵包屑在中螢幕以上才顯示
  2. 響應式標題大小:手機 fs-3,中螢幕 fs-2,大螢幕 fs-1
  3. Flexbox:手機垂直排列,平板以上水平排列
  4. 在平板以上才有右側間距和下方間距
  5. 標籤自動換行 (mb-1)
  6. 響應式文字大小:手機 fs-6,中螢幕以上 fs-5
  7. 在小螢幕以上顯示完整文字
  8. 在小螢幕顯示簡化版本(只有圖示)
  9. 更新時間只在中螢幕以上顯示

Bootstrap 顯示工具類別

Bootstrap 提供了方便的顯示/隱藏工具類別:

  • d-none: 隱藏元素
  • d-{breakpoint}-block: 在指定斷點以上顯示為 block
  • d-{breakpoint}-inline: 在指定斷點以上顯示為 inline
  • d-{breakpoint}-none: 在指定斷點以上隱藏

範例:

  • d-none d-md-block: 預設隱藏,中螢幕以上顯示
  • d-block d-md-none: 預設顯示,中螢幕以上隱藏

響應式導覽列

我們的 base.html 已經使用了響應式導覽列,讓我們檢視它的運作原理:

templates/base.html
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container">
    <span class="navbar-brand">Django 大冒險</span>  <!-- (1)! -->
    <button class="navbar-toggler"
            type="button"
            data-bs-toggle="collapse"
            data-bs-target="#navbarNav">  <!-- (2)! -->
      <span class="navbar-toggler-icon"></span>  <!-- (3)! -->
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">  <!-- (4)! -->
      <ul class="navbar-nav ms-auto">
        <li class="nav-item">
          <a class="nav-link" href="{% url 'article_list' %}">文章列表</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="{% url 'admin:index' %}">管理後台</a>
        </li>
      </ul>
    </div>
  </div>
</nav>
  1. 品牌名稱,在所有尺寸都顯示
  2. 漢堡選單按鈕,在小螢幕顯示
  3. 漢堡圖示(三條線)
  4. 可收合的選單內容

導覽列運作方式

  • 大螢幕 (≥992px):
  • 選單項目水平排列
  • 漢堡按鈕隱藏

  • 小螢幕 (<992px):

  • 選單收合,只顯示品牌 logo 和漢堡按鈕
  • 點擊漢堡按鈕展開垂直選單

navbar-expand-* 說明

navbar-expand-{breakpoint} 控制導覽列何時從收合變成展開:

  • navbar-expand-sm: 在 ≥576px 展開
  • navbar-expand-md: 在 ≥768px 展開
  • navbar-expand-lg: 在 ≥992px 展開(我們使用這個)
  • navbar-expand-xl: 在 ≥1200px 展開

測試響應式設計

使用瀏覽器開發者工具

所有現代瀏覽器都內建響應式設計模式:

Chrome / Edge

  1. F12 開啟開發者工具
  2. Ctrl+Shift+M (Mac: Cmd+Shift+M) 切換裝置模式
  3. 選擇不同裝置或自訂尺寸

Firefox

  1. F12 開啟開發者工具
  2. Ctrl+Shift+M (Mac: Cmd+Option+M) 切換響應式設計模式

Safari

  1. 開啟「開發」選單(偏好設定 → 進階 → 顯示「開發」選單)
  2. 「開發」→「進入響應式設計模式」

常見測試尺寸

裝置 寬度 × 高度
iPhone SE 375 × 667
iPhone 12 Pro 390 × 844
iPad 768 × 1024
iPad Pro 1024 × 1366
Desktop HD 1920 × 1080

測試檢查清單

測試響應式網站時,應該檢查:

  • 文字是否清晰可讀(沒有太小)
  • 按鈕是否夠大,方便點擊
  • 圖片是否正確縮放
  • 導覽列是否正常運作
  • 表單是否易於填寫
  • 內容是否需要左右捲動(應該避免)
  • 欄位在不同尺寸下是否正確排列
  • 隱藏/顯示的元素是否符合預期

響應式設計最佳實踐

1. 行動優先 (Mobile First)

先設計手機版,再擴展到大螢幕:

/* 預設樣式(手機) */
.card {
  width: 100%;
}

/* 平板以上 */
@media (min-width: 768px) {
  .card {
    width: 50%;
  }
}

/* 桌機以上 */
@media (min-width: 992px) {
  .card {
    width: 33.333%;
  }
}

2. 觸控友善

手機使用者用手指點擊,按鈕應該夠大:

/* 按鈕至少 44×44 像素 */
.btn {
  min-height: 44px;
  min-width: 44px;
}

Bootstrap 的按鈕預設已經符合這個標準。

3. 適當的文字大小

/* 手機最小 16px,避免自動縮放 */
body {
  font-size: 16px;
}

/* 標題在大螢幕可以更大 */
@media (min-width: 992px) {
  h1 {
    font-size: 3rem;
  }
}

4. 優化圖片

<!-- 使用 srcset 提供不同尺寸的圖片 -->
<img
  src="image-800w.jpg"
  srcset="image-400w.jpg 400w, image-800w.jpg 800w, image-1200w.jpg 1200w"
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="說明文字"
/>

5. 避免固定寬度

/* 不好 */
.container {
  width: 960px;
}

/* 好 */
.container {
  max-width: 1200px;
  width: 100%;
  padding: 0 15px;
}

Bootstrap 的 .container 已經處理好這些細節。

常見問題

RWD 和 Adaptive Design 有什麼不同?

  • RWD (響應式設計): 使用流動格線和 media queries,在所有尺寸都能平滑適應
  • Adaptive Design (自適應設計): 為特定尺寸設計不同版本(如手機版、平板版、桌機版)

RWD 更靈活,維護成本較低,是目前的主流方式。

要支援哪些螢幕尺寸?

建議至少支援:

  • 手機: 375px - 428px
  • 平板: 768px - 1024px
  • 桌機: 1200px 以上

但 RWD 的優勢就是能適應任何尺寸,不需要精確為每個裝置設計。

Bootstrap Grid 一定要用嗎?

不一定。現代 CSS 也提供了強大的佈局工具:

  • Flexbox: 一維佈局
  • CSS Grid: 二維佈局

但 Bootstrap Grid 提供了:

  • 現成的響應式斷點
  • 跨瀏覽器相容性
  • 快速開發

對於大多數專案,Bootstrap Grid 是很好的選擇。

如何處理表格的響應式?

表格在小螢幕上很難顯示,有幾種解決方案:

  1. 水平捲動:

    <div class="table-responsive">
    <table class="table">
        <!-- 表格內容 -->
    </table>
    </div>
    
  2. 轉換為卡片式佈局 (手機上)

  3. 隱藏次要欄位 (使用 d-none d-md-table-cell)

任務結束

完成!

恭喜你完成了這個章節!現在你已經:

  • 了解 RWD 網頁設計的概念與重要性
  • 深入理解 Bootstrap Grid 系統
  • 優化文章列表與詳細頁面的響應式設計
  • 學習響應式設計的測試方法

補充說明

響應式設計是現代網頁開發的必備技能。掌握 RWD 後:

  • 網站能在任何裝置上提供良好體驗
  • 提升網站的可訪問性和 SEO
  • 降低開發和維護成本

在實際專案中,建議:

  • 行動優先: 先設計手機版,再擴展到桌機版
  • 測試多種裝置: 不只測試常見尺寸,也要測試極端情況
  • 考慮觸控操作: 按鈕要夠大,間距要適當
  • 優化效能: 手機通常網速較慢,要注意載入時間

下一步可以學習:

  • CSS Flexbox 和 Grid 的進階應用
  • 使用 Lighthouse 測試效能和可訪問性
  • 圖片優化技術(WebP、lazy loading)
  • Progressive Web App (PWA)