【Tailwind CSS 教學】#03 響應式設計與狀態變化

Tailwind CSS 響應式設計小測驗

測試你對響應式斷點與狀態變體的理解

1 Tailwind 的 Mobile-First 設計理念是什麼意思?
解說:Tailwind 採用 Mobile-First 設計,沒有前綴的 class 會套用到所有螢幕尺寸,加上斷點前綴(如 md:)後,只會在該斷點「以上」生效。例如 md:text-lg 只在 768px 以上才會套用。
2 以下程式碼 <div class="hidden md:block"> 的效果是什麼?
解說:hidden 是預設樣式,套用到所有螢幕(隱藏元素)。md:block 在 768px 以上覆蓋為 display: block,所以效果是「手機上隱藏,平板以上顯示」。這是響應式導覽列常用的技巧。
3 哪個 Tailwind class 可以讓按鈕在滑鼠移入時變成深藍色背景?
解說:hover: 前綴用於滑鼠移入狀態。focus: 是獲得焦點時(點擊或 Tab),active: 是按住滑鼠時。Tailwind 不使用 onmouseover: 這種 JavaScript 事件名稱作為前綴。
4 如何讓滑鼠移到父元素時,子元素的文字變色?
解說:要實現「滑鼠移到父元素時,子元素跟著變化」,需要在父元素加上 group class,然後在子元素使用 group-hover: 前綴。這是 Tailwind 的群組狀態功能。
5 Tailwind 的 dark: 前綴預設是根據什麼來決定深色模式?
解說:Tailwind 預設使用 media 策略,根據使用者的系統偏好設定(prefers-color-scheme)自動切換深色模式。如果想手動控制,可以在 tailwind.config.js 設定 darkMode: 'class',然後在 HTML 加上 dark class。
0/5

本文是「Tailwind CSS 教學」系列第 3 篇,共 4 篇。
難度:L2-進階

前言

當你用 Tailwind 做出一個漂亮的按鈕後,下一個問題通常是:「怎麼讓它在手機上也好看?」以及「滑鼠移上去時要怎麼變色?」

這就是本篇要教的兩大主題:響應式設計狀態變化。Tailwind 用一套非常直覺的「前綴」語法來處理這些需求,讓你不用寫任何 media query 或 :hover 選擇器。

響應式斷點:Mobile-First 設計

什麼是 Mobile-First?

Tailwind 採用「行動優先」的設計理念。這代表:

  • 沒有前綴的 class 會套用到所有螢幕尺寸
  • 加上斷點前綴後,只會在該斷點以上生效

來看一個例子:

<div class="text-sm md:text-base lg:text-lg">
  這段文字會隨螢幕大小改變
</div>
Code language: HTML, XML (xml)

這段程式碼的意思是:

  • 預設(手機):text-sm(小字)
  • 中型螢幕以上:text-base(正常字)
  • 大型螢幕以上:text-lg(大字)

五個標準斷點

Tailwind 提供五個預設斷點:

前綴 最小寬度 常見裝置
sm 640px 大手機、小平板
md 768px 平板(直式)
lg 1024px 平板(橫式)、小筆電
xl 1280px 桌上型電腦
2xl 1536px 大螢幕

重要觀念:斷點前綴代表「這個寬度以上」,不是「剛好這個寬度」。

<!-- lg:hidden 表示「1024px 以上時隱藏」 -->
<div class="block lg:hidden">只在手機和平板顯示</div>
<div class="hidden lg:block">只在桌面顯示</div>
Code language: HTML, XML (xml)

實作:響應式文字大小

讓我們看一個完整的範例:

<h1 class="text-xl sm:text-2xl md:text-3xl lg:text-4xl xl:text-5xl">
  響應式標題
</h1>

<p class="text-sm md:text-base lg:text-lg leading-relaxed md:leading-loose">
  這是一段響應式內文。在小螢幕上字比較小、行距正常;
  在大螢幕上字比較大、行距寬鬆,讓閱讀更舒適。
</p>
Code language: HTML, XML (xml)

解讀這段程式碼:

  1. text-xl 是手機上的預設值
  2. sm:text-2xl 在 640px 以上變大
  3. 以此類推,螢幕越大字越大

實作響應式導覽列

這是最常見的響應式需求:手機顯示漢堡選單,桌面顯示完整選單。

基本結構

<nav class="bg-gray-800 text-white p-4">
  <div class="flex justify-between items-center">
    <!-- Logo -->
    <div class="text-xl font-bold">MyApp</div>

    <!-- 漢堡按鈕:只在手機顯示 -->
    <button class="md:hidden">
      <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
              d="M4 6h16M4 12h16M4 18h16"/>
      </svg>
    </button>

    <!-- 桌面選單:只在 md 以上顯示 -->
    <div class="hidden md:flex space-x-6">
      <a href="#" class="hover:text-gray-300">首頁</a>
      <a href="#" class="hover:text-gray-300">產品</a>
      <a href="#" class="hover:text-gray-300">關於</a>
      <a href="#" class="hover:text-gray-300">聯絡</a>
    </div>
  </div>
</nav>
Code language: HTML, XML (xml)

關鍵 class 解讀:

  • md:hidden:在 768px 以上隱藏漢堡按鈕
  • hidden md:flex:預設隱藏,768px 以上顯示為 flex

手機選單展開(需要 JavaScript)

完整的漢堡選單需要 JavaScript 控制展開/收合:

<nav class="bg-gray-800 text-white">
  <div class="p-4 flex justify-between items-center">
    <div class="text-xl font-bold">MyApp</div>

    <!-- 漢堡按鈕 -->
    <button id="menuBtn" class="md:hidden">
      <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
              d="M4 6h16M4 12h16M4 18h16"/>
      </svg>
    </button>

    <!-- 桌面選單 -->
    <div class="hidden md:flex space-x-6">
      <a href="#">首頁</a>
      <a href="#">產品</a>
      <a href="#">關於</a>
    </div>
  </div>

  <!-- 手機選單(預設隱藏) -->
  <div id="mobileMenu" class="hidden md:hidden px-4 pb-4">
    <a href="#" class="block py-2">首頁</a>
    <a href="#" class="block py-2">產品</a>
    <a href="#" class="block py-2">關於</a>
  </div>
</nav>

<script>
  document.getElementById('menuBtn').addEventListener('click', function() {
    document.getElementById('mobileMenu').classList.toggle('hidden');
  });
</script>
Code language: HTML, XML (xml)

注意 md:hidden 在手機選單上的作用:確保桌面版不會顯示這個區塊。

狀態變體:互動效果

基本狀態前綴

Tailwind 提供各種狀態前綴,讓你控制不同互動狀態的樣式:

前綴 觸發條件
hover: 滑鼠移入
focus: 獲得焦點(點擊或 Tab)
active: 按住滑鼠
disabled: 禁用狀態
focus-visible: 鍵盤導航獲得焦點

實作互動按鈕

<!-- 基本按鈕 -->
<button class="bg-blue-500 text-white px-4 py-2 rounded
               hover:bg-blue-600
               focus:outline-none focus:ring-2 focus:ring-blue-300
               active:bg-blue-700">
  點我
</button>

<!-- 禁用狀態 -->
<button class="bg-blue-500 text-white px-4 py-2 rounded
               hover:bg-blue-600
               disabled:bg-gray-400 disabled:cursor-not-allowed"
        disabled>
  已禁用
</button>
Code language: HTML, XML (xml)

解讀:

  • hover:bg-blue-600:滑鼠移入時背景變深
  • focus:ring-2:獲得焦點時顯示外框
  • active:bg-blue-700:按下時背景更深
  • disabled:bg-gray-400:禁用時變灰色
  • disabled:cursor-not-allowed:禁用時顯示禁止游標

表單輸入框

<input type="text"
       class="border border-gray-300 rounded px-3 py-2 w-full
              focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500
              placeholder:text-gray-400"
       placeholder="請輸入姓名">
Code language: HTML, XML (xml)

這個輸入框:

  • 預設有灰色邊框
  • 獲得焦點時邊框變藍色,並顯示外圈光暈
  • placeholder 文字是淺灰色

群組狀態:group 和 group-hover

有時候你希望「滑鼠移到父元素時,子元素跟著變化」。這時需要用 group

<a href="#" class="group block p-4 bg-white rounded-lg shadow
                   hover:bg-blue-500">
  <h3 class="text-lg font-bold text-gray-900
             group-hover:text-white">
    卡片標題
  </h3>
  <p class="text-gray-600
            group-hover:text-blue-100">
    滑鼠移到卡片上,文字會變色
  </p>
</a>
Code language: HTML, XML (xml)

運作方式:

  1. 父元素加上 group class
  2. 子元素使用 group-hover: 前綴
  3. 當滑鼠移到父元素時,所有 group-hover: 樣式生效

巢狀群組

如果有多層群組,可以用命名群組:

<div class="group/card p-4 bg-white rounded-lg hover:bg-gray-50">
  <div class="group/title flex items-center">
    <h3 class="group-hover/title:underline">標題</h3>
    <span class="group-hover/card:text-blue-500">圖示</span>
  </div>
</div>
Code language: HTML, XML (xml)

group/cardgroup/title 是不同的群組,各自獨立運作。

深色模式:dark: 前綴

啟用深色模式

Tailwind 支援兩種深色模式策略:

1. Media 策略(預設) 根據系統設定自動切換:

// tailwind.config.js
module.exports = {
  darkMode: 'media', // 這是預設值,可以不寫
}
Code language: JavaScript (javascript)

2. Class 策略 手動控制,需在 HTML 加上 dark class:

// tailwind.config.js
module.exports = {
  darkMode: 'class',
}
Code language: JavaScript (javascript)
<!-- 在 html 或 body 加上 dark class -->
<html class="dark">
  ...
</html>
Code language: HTML, XML (xml)

使用 dark: 前綴

<div class="bg-white dark:bg-gray-800
            text-gray-900 dark:text-gray-100
            p-6 rounded-lg">
  <h2 class="text-xl font-bold text-gray-800 dark:text-white">
    標題
  </h2>
  <p class="text-gray-600 dark:text-gray-300">
    這段文字在深色模式會變成淺色
  </p>
</div>
Code language: HTML, XML (xml)

深色模式按鈕

<button class="bg-blue-500 dark:bg-blue-600
               text-white
               hover:bg-blue-600 dark:hover:bg-blue-500
               px-4 py-2 rounded">
  支援深色模式的按鈕
</button>
Code language: HTML, XML (xml)

注意 dark:hover: 的組合:先是深色模式,再是 hover 狀態。

組合斷點與狀態變體

Tailwind 最強大的地方是可以自由組合這些前綴:

<button class="bg-blue-500 text-white px-4 py-2 rounded
               hover:bg-blue-600
               md:px-6 md:py-3
               md:hover:bg-blue-700
               dark:bg-blue-600
               dark:hover:bg-blue-500
               lg:dark:hover:bg-blue-400">
  複合按鈕
</button>
Code language: HTML, XML (xml)

這個按鈕:

  • 手機:px-4 py-2,hover 時 bg-blue-600
  • 平板以上:px-6 py-3,hover 時 bg-blue-700
  • 深色模式:背景 bg-blue-600
  • 深色模式 hover:bg-blue-500
  • 大螢幕深色模式 hover:bg-blue-400

前綴順序

當組合多個前綴時,順序是:

{響應式}:{深色模式}:{狀態}:{樣式}

例如:lg:dark:hover:bg-blue-400

實作練習:響應式卡片元件

讓我們做一個完整的響應式卡片網格:

<!-- 卡片容器:手機單欄、平板雙欄、桌面三欄 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6">

  <!-- 單張卡片 -->
  <div class="group bg-white dark:bg-gray-800 rounded-lg shadow-md
              hover:shadow-xl transition-shadow duration-300">
    <!-- 圖片區 -->
    <div class="relative overflow-hidden rounded-t-lg">
      <img src="image.jpg" alt="產品圖"
           class="w-full h-48 object-cover
                  group-hover:scale-105 transition-transform duration-300">
    </div>

    <!-- 內容區 -->
    <div class="p-4 md:p-6">
      <h3 class="text-lg md:text-xl font-bold
                 text-gray-900 dark:text-white
                 group-hover:text-blue-600 dark:group-hover:text-blue-400">
        產品名稱
      </h3>
      <p class="mt-2 text-sm md:text-base
                text-gray-600 dark:text-gray-300">
        這是產品描述,在小螢幕上字會小一點。
      </p>

      <!-- 按鈕 -->
      <button class="mt-4 w-full md:w-auto
                     bg-blue-500 dark:bg-blue-600
                     text-white px-4 py-2 rounded
                     hover:bg-blue-600 dark:hover:bg-blue-500
                     focus:outline-none focus:ring-2 focus:ring-blue-300
                     active:bg-blue-700
                     disabled:bg-gray-400 disabled:cursor-not-allowed
                     transition-colors duration-200">
        加入購物車
      </button>
    </div>
  </div>

  <!-- 更多卡片... -->
</div>
Code language: HTML, XML (xml)

這個範例包含了:

響應式設計

  • grid-cols-1 md:grid-cols-2 lg:grid-cols-3:響應式欄位數
  • p-4 md:p-6:響應式內距
  • text-lg md:text-xl:響應式文字大小
  • w-full md:w-auto:手機上按鈕滿版,桌面上自動寬度

狀態變體

  • hover:shadow-xl:hover 時陰影變深
  • group-hover:scale-105:hover 時圖片放大
  • group-hover:text-blue-600:hover 時標題變色

深色模式

  • dark:bg-gray-800:深色背景
  • dark:text-white:深色文字
  • dark:group-hover:text-blue-400:深色模式的 hover 顏色

過渡效果

  • transition-shadow duration-300:陰影動畫
  • transition-transform duration-300:縮放動畫
  • transition-colors duration-200:顏色動畫

讀懂響應式程式碼的技巧

當你看到一長串 Tailwind class 時:

  1. 先找沒有前綴的 class:這是手機上的預設樣式
  2. 依序找 sm、md、lg、xl:了解在不同螢幕的變化
  3. 找狀態前綴:hover、focus、active 等互動效果
  4. 找 dark 前綴:深色模式的樣式
  5. 找 group 相關:群組互動效果

範例解讀:

<div class="p-4 md:p-6 lg:p-8 hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700">
Code language: JavaScript (javascript)
  • 手機:p-4
  • 平板:p-6
  • 桌面:p-8
  • hover:bg-gray-50
  • 深色模式:bg-gray-800
  • 深色模式 hover:bg-gray-700

小結

本篇介紹了 Tailwind CSS 的響應式設計和狀態變化:

  • Mobile-First 設計:沒有前綴套用所有螢幕,斷點前綴代表「以上」
  • 五個標準斷點:sm、md、lg、xl、2xl
  • 狀態變體:hover、focus、active、disabled 等前綴
  • 群組狀態:group 配合 group-hover 實現父子連動
  • 深色模式:dark 前綴,可選 media 或 class 策略
  • 前綴組合:響應式 + 深色 + 狀態可以自由組合

下一篇將介紹 Tailwind 的進階技巧:自訂設定、抽取元件、以及與前端框架的整合方式。

延伸閱讀

Tailwind CSS 響應式設計進階挑戰

情境題與錯誤診斷 – 測試你的實戰能力

情境題
1 你要實作一個響應式導覽列:手機顯示漢堡選單按鈕,平板以上顯示完整選單連結。以下哪組 class 最適合?
需求:漢堡按鈕在 768px 以下顯示,768px 以上隱藏。選單連結相反。
解說:漢堡按鈕預設顯示(button 本來就是 block),加上 md:hidden 在 768px 以上隱藏。選單預設 hidden 隱藏,md:flex 在 768px 以上顯示為 flex 排列。選項 A 也可行但 md:flex 更常用於水平排列選單。選項 D 用錯斷點(sm 是 640px)。
錯誤診斷
2 這段程式碼想讓卡片在 hover 時,內部標題變成藍色,但沒有效果。問題在哪?
<div class=”p-4 bg-white rounded-lg hover:shadow-lg“> <h3 class=”text-gray-900 group-hover:text-blue-600“> 標題 </h3> <p class=”text-gray-600“>內容</p> </div>
解說:要使用 group-hover: 功能,必須在父元素加上 group class。正確寫法是 <div class="group p-4 bg-white...">。沒有 group class,Tailwind 不知道要監聽哪個元素的 hover 狀態。
情境題
3 你的網站需要支援深色模式,且希望讓使用者能手動切換(不跟隨系統設定)。需要做什麼設定?
需求:提供一個切換按鈕,點擊後在深色/淺色模式間切換,不受系統設定影響。
解說:Tailwind 提供兩種深色模式策略:media(預設,跟隨系統設定)和 class(手動控制)。要實現手動切換,必須設定 darkMode: 'class',然後用 JavaScript 在 <html> 元素上新增或移除 dark class。不存在 darkMode: 'manual' 這個選項。
錯誤診斷
4 以下程式碼想實現「大螢幕深色模式時 hover 變成淺藍色」,但前綴順序有問題。正確寫法是什麼?
<button class=”bg-blue-500 hover:lg:dark:bg-blue-300“> 按鈕 </button>
解說:Tailwind 前綴的正確順序是:{響應式}:{深色模式}:{狀態}:{樣式}。所以「大螢幕 + 深色模式 + hover」的正確寫法是 lg:dark:hover:bg-blue-300。先指定螢幕大小(lg),再指定顏色模式(dark),最後指定互動狀態(hover)。
綜合應用
5 你要實作一個響應式卡片網格:手機單欄、平板雙欄、桌面三欄。以下哪個 class 組合最正確?
<div class=”/* 這裡該放什麼? */“> <div>卡片 1</div> <div>卡片 2</div> <div>卡片 3</div> </div>
解說:Tailwind 是 Mobile-First,所以要從小螢幕開始設定:grid-cols-1(手機預設)、md:grid-cols-2(平板覆蓋為雙欄)、lg:grid-cols-3(桌面覆蓋為三欄)。選項 A 的順序顛倒了,從大到小的寫法不符合 Mobile-First 原則且效果會錯誤。選項 D 缺少預設值,手機上會沒有欄位設定。
0/5

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *