---
# System prepended metadata

title: Tailwind概述

---

## CSS框架(CSS framework)
### 概述
* 框架的誕生是為了解決現存問題以及提升開發效率
* 使用框架可協助開發者快速建構網頁，且具備一致性、便於維護等優點
* 相對地，可能有較難客製化的缺點
* 由於採取的CSS設計模式不同，每個框架有各自的設計理念，應視專案的需求挑選適合的框架

### 什麼情況適合使用CSS框架？
* 適合用於：
    1. 快速開發
    2. 統一設計風格
    3. 確保跨瀏覽器兼容性
    4. 需維護的大型專案
* 個人偏好、框架是否有開發者社群支援也是一種考量
* 何時或許該選擇直接撰寫CSS？
    1. 需要較多客製化的專案
    2. 規模較小的專案
    3. 框架不提供專案需要的元件

## Tailwind三大核心概念
### 比較utility class及傳統class
| | utility class | traditional class |
| -- | -- | -- |
| 命名規則 | 名稱即樣式效果 | 追求語義化 |
| 功能 | 用於呈現單一樣式效果 | 可能包含多種結構和樣式設計 |

### 1. 功能優先 Utility-First
* 利用Tailwind原生utility class組裝出需要的元件樣式，不需額外撰寫任何CSS，故不會隨著網頁內容增加，使得CSS跟著線性成長

    ```html
    <div class="py-8 px-8 max-w-sm mx-auto bg-white rounded-xl shadow-lg space-y-2 sm:py-4 sm:flex sm:items-center sm:space-y-0 sm:space-x-6">
      <img class="block mx-auto h-24 rounded-full sm:mx-0 sm:shrink-0" src="/img/erin-lindford.jpg" alt="Woman's Face" />
      <div class="text-center space-y-2 sm:text-left">
        <div class="space-y-0.5">
          <p class="text-lg text-black font-semibold">
            Erin Lindford
          </p>
          <p class="text-slate-500 font-medium">
            Product Engineer
          </p>
        </div>
        <button class="px-4 py-1 text-sm text-purple-600 font-semibold rounded-full border border-purple-200 hover:text-white hover:bg-purple-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-offset-2">Message</button>
      </div>
    </div>
    ```

* 擺脫永無止盡的的class命名(即使是單純的flex容器也需要命名)，且不必擔心class名稱重複
	    
  ```html
  <div class="nav-bar">
    <ul class="nav-container">
      <li class="nav-item">...</li>
      <li class="nav-item">...</li>
      <li class="nav-item">...</li>
    </ul>
  </div>
  ```
* 如果將整個CSS style sheet視為global scope，HTML class name則屬於local scope，故進行變更時更加安全，不必擔心發生其他連帶影響
* utility class可以視為類`inline styles`，但具備後者沒有的優點
	1. `inline styles`中樣式的值依然為自訂，使用utility class可維持整體UI在視覺上的一致性
	2. 可進行響應式設計，也可針對`hover`等狀態進行樣式設計

### 2. 設計樣式變化
#### Hover、Focus以及其他狀態
* 所有utility class皆可視需求，在class name之前加上modifier作為前綴詞來規範不同狀態或模式下的樣式設計
    * 想製造按鈕hover效果，只需組合`hover:`、`bg-sky-700`即可

      ```html
      <button class="bg-sky-600 hover:bg-sky-700 ...">
        Save changes
      </button>
      ```
    * 相較之下傳統的CSS，`.btn-primary:hover {}`和`background-color: #0369a1;`都須自行撰寫，且無法在他處重複使用

      ```css
      .btn-primary {
        background-color: #0ea5e9;
      }
      .btn-primary:hover {
        background-color: #0369a1;
      }
      ```
* 可使用的修飾符Modifiers
    * 偽類 `pseudo-classes`
        * `:hover`, `:first-child`...
    * 偽元素 `pseudo-elements`
        * `::before`, `::after`, `::placeholder`...
    * Media queries
        * responsive breakpoints
        * dark modes
        * `prefers-reduced-motion`
* 屬性選擇器(Attribute selectors)
    * `h1[class="title"]`, `rtl`(right-to-left)...

* Modifiers可進一步堆疊使用，範例的按鈕為深色模式中medium斷點的hover變化

  ```html
  <button class="dark:md:hover:bg-fuchsia-600 ...">
    Save changes
  </button>
  ```
* 自定義的class也可利用modifier前綴(需在`@layers`中定義或使用`addVariant`API加入plugin)


#### 響應式設計 Responsive Design
**預設五種斷點設計**
| Breakpoint prefix | Minimum width | CSS |
|---|---|---|
| `sm` | 640px | `@media (min-width: 640px) { ... }` |
| `md` | 768px | `@media (min-width: 768px) { ... }` |
| `lg` | 1024px | `@media (min-width: 1024px) { ... }` |
| `xl` | 1280px | `@media (min-width: 1280px) { ... }` |
| `2xl` | 1536px | `@media (min-width: 1536px) { ... }` |
* 斷點設計只有`min-width`，沒有`max-width`

**手機優先 Mobile First**
* 預設為手機優先，撰寫時不需加上前綴詞，留意`sm:`的斷點設計為`min-width: 640px`
	* 螢幕尺寸640px以上時`文字置中`
	  ```html
	  <div class="sm:text-center"></div>
	  ```
	* 手機裝置時`文字置中`，螢幕尺寸640px以上時`文字靠左`
	    
	  ```html
	  <div class="text-center sm:text-left"></div>
	  ```
* 可在`tailwind.config.js`設定檔中自訂斷點

**深色模式 Dark Mode**
* 使用`dark:`前綴詞
* 可在`tailwind.config.js`設定檔中設定切換模式
    * 手動切換：`class`
    * 作業系統自動轉換：`media`

### 3. 自定義
#### 管理可重複使用的樣式設計 Reusing Styles
**利用`@apply`進行提取**
- 當一個使用頻率高的html tag的class name越來越長
    - 以按鈕為例，功能性class name相當長

      ```html
      <button class="py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75">
        Save changes
      </button>
      ```
    - 利用`@apply`將class name改寫成更加簡潔的自訂義代稱`btn-primary`

      ```html
      <button class="btn-primary">
        Save changes
      </button>
      ```

      ```css
      @tailwind base;
      @tailwind components;
      @tailwind utilities;

      @layer components {
        .btn-primary {
          @apply py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
        }
      }
      ```
- 應避免單純為了「看起來」更整潔而過度使用`@apply`，創造大量自定義的CSS反而本末倒置、放棄了Tailwind的優點
- 盡量在高度重複利用的小元件上使用`@apply`，例如按鈕
- 在搭配使用前端框架的情況下，直接製作成前端框架的元件，就不必使用`@apply`

### 增加自訂樣式 Adding Custom Styles
- 在`tailwind.config.js`中的`theme`中新增自訂義的樣式設計

  ```javascript
  module.exports = {
    theme: {
      colors: {
        'blue': '#1fb6ff',
        'pink': '#ff49db',
        'orange': '#ff7849',
        'green': '#13ce66',
        'gray-dark': '#273444',
        'gray': '#8492a6',
        'gray-light': '#d3dce6',
      },
      fontFamily: {
        sans: ['Graphik', 'sans-serif'],
        serif: ['Merriweather', 'serif'],
      }
    }
  }
  ```
- `[]`表示法
    - 產生使用**任意值**的class name：可用於各種修飾符

      ```html
      <div class="bg-[#bada55] text-[22px] before:content-['Festivus']">
        <!-- ... -->
      </div>
      ```
    - 產生使用**任意屬性**的class name：可用於各種修飾符

      ```html
      <div class="[mask-type:luminance] hover:[mask-type:alpha]">
        <!-- ... -->
      </div>
      ```
- 使用`@layer`新增自訂義CSS
    - 新增基本樣式：在`base`中自訂`h1`、`h2`

      ```css
      @tailwind base;
      @tailwind components;
      @tailwind utilities;

      @layer base {
        h1 {
          @apply text-2xl;
        }
        h2 {
          @apply text-xl;
        }
        /* ... */
      }
      ```
        - 樣式層級權重由低到高：`base`->`components`->`utilities`
    - 新增元件(components)：在`components`新增較複雜的樣式設計、第三方組件等

      ```css
      @tailwind base;
      @tailwind components;
      @tailwind utilities;

      @layer components {
        .card {
          background-color: theme('colors.white');
          border-radius: theme('borderRadius.lg');
          padding: theme('spacing.6');
          box-shadow: theme('boxShadow.xl');
        }
        /* ... */
      }
      ```
    - 注意：利用`@layer`新增的自定義CSS，只有html中實際使用的樣式才會被編譯進CSS中
### 函式與指令 Functions & Directives
#### 指令
- `@tailwind`
    * 將`base`、`components`、`utilities`、`variants`插入CSS中
- `@layer`
    - `@layer`中新增的自定義CSS皆可使用修飾符
- `@apply`
    - `@apply`中的樣式規則中的`!important`會被移除

      ```css
      /* Input */
      .foo {
        color: blue !important;
      }

      .bar {
        @apply foo;
      }
      ```

      ```css
      /* Output */
      .foo {
        color: blue !important;
      }

      .bar {
        color: blue;
      }
      ```
    - 若要保留`!important`，則將`!important`撰寫在`@apply`的句尾

      ```css
      /* Input */
      .btn {
        @apply font-bold py-2 px-4 rounded !important;
      }
      ```

      ```css
      /* Output */
      .btn {
        font-weight: 700 !important;
        padding-top: .5rem !important;
        padding-bottom: .5rem !important;
        padding-right: 1rem !important;
        padding-left: 1rem !important;
        border-radius: .25rem !important;
      }
      ```
#### 函式
- 利用`theme()`函式搭配點記法取得config中值

  ```css
  .content-area {
    height: calc(100vh - theme('spacing.12'));
  }
  ```
    - 利用`[]`取得包含小數點的值

      ```css
      .content-area {
        height: calc(100vh - theme('spacing[2.5]'));
      }
      ```
- `screen()`函式中可使用名稱引用斷點設定

  ```css
  @media screen(sm) {
    /* ... */
  }
  ```
  
## 手刻 vs Tailwind？
### [Tailwind官網範例](https://tailwindcss.tw/docs/utility-first)
![](https://hackmd.io/_uploads/SktW7E9Za.png)

- 傳統寫法
    - HTML
      ```html
      <div class="chat-notification">
        <div class="chat-notification-logo-wrapper">
          <img class="chat-notification-logo" src="/img/logo.svg" alt="ChitChat Logo">
        </div>
        <div class="chat-notification-content">
          <h4 class="chat-notification-title">ChitChat</h4>
          <p class="chat-notification-message">You have a new message!</p>
        </div>
      </div>
      ```
    - CSS
      ```css
      .chat-notification {
        display: flex;
        max-width: 24rem;
        margin: 0 auto;
        padding: 1.5rem;
        border-radius: 0.5rem;
        background-color: #fff;
        box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
      }
      .chat-notification-logo-wrapper {
        flex-shrink: 0;
      }
      .chat-notification-logo {
        height: 3rem;
        width: 3rem;
      }
      .chat-notification-content {
        margin-left: 1.5rem;
        padding-top: 0.25rem;
      }
      .chat-notification-title {
        color: #1a202c;
        font-size: 1.25rem;
        line-height: 1.25;
      }
      .chat-notification-message {
        color: #718096;
        font-size: 1rem;
        line-height: 1.5;
      }
      ```
- Tailwind寫法
    - HTML
      ```html
      <div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg flex items-center space-x-4">
        <div class="shrink-0">
          <img class="h-12 w-12" src="/img/logo.svg" alt="ChitChat Logo">
        </div>
        <div>
          <div class="text-xl font-medium text-black">ChitChat</div>
          <p class="text-slate-500">You have a new message!</p>
        </div>
      </div>
      ```
  
### 為什麼要用Tailwind？
- 原子化、元件化概念應用：減少重複工作
- class name名稱具備較佳的語義化
- 擺脫命名地獄
- 輕量：可利用PurgeCSS進行打包瘦身

## 參考文章
- 官方網站：[Tailwind CSS](https://tailwindcss.tw)
- [淺談 Atomic CSS 的發展背景與 Tailwind CSS](https://blog.huli.tw/2022/05/23/atomic-css-and-tailwind-css/)
- [淺談 Tailwind CSS](https://medium.com/@hayato.chang/淺談-tailwind-css-4153d86eb661)
- [客觀評價 TailwindCSS](https://medium.com/@nightspirit622/客觀評價-tailwindcss-af27581f6d9)
- [排版神器 Tailwind CSS～和兔兔一起快速上手漂亮的元件開發！系列](https://ithelp.ithome.com.tw/users/20138853/ironman/3928)