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