## 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)

- 傳統寫法
- 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)