# 簡介 React.js 中的 Tailwind CSS 與 clsx > 文中的開發環境:React, Tailwind v3 ## ESLint - 安裝 [eslint-plugin-tailwindcss](https://www.npmjs.com/package/eslint-plugin-tailwindcss) 來規範 TailwindCSS 的 class 寫法 ## TailwindCSS > TailwindCSS 是一個以原子化 CSS 為主軸的框架,對於習慣手刻的開發者來說有著十分友好的學習曲線,因每個 class 的名稱都有對應的樣式屬性,就像在一般的 class 中撰寫樣式一樣。 ### 主要的好處為: 1. 因每個 class 都是原子化的設計,一般使用場景中所需的樣式皆可透過對應的 class 名稱來取用,所以專案的樣式檔與 class 數量並不會隨著專案變大而無限擴展。 2. 除此之外,也因為 class 是直接寫在 html 上的,所以也能避免在 style 檔案中撰寫過多層的 class 選擇器的情形(像是:.container -> button -> span)。 3. 另外也可以透過 tailwind.config.js 來統一設定專案中的色彩系統、文字大小、背景圖片、動畫效果等,將 guide line 統一在一個設定檔案中方便查找、遵循。 ### 而其中不可諱言的短處則為: 1. 當樣式過於複雜時會導致 className 過長,像毛毛蟲一樣很難看懂 - 而這可以透過將 className 賦值給變數後使用 - 或是在 `css-modules` 檔案中,於自定義的 className 中透過 `@apply tailwindClassName` 來使用 tailwind 的 class - 也可在 clsx 中透過換行來增加可讀性。 2. 透過 devTool 檢查的時候,只會看到一大串 className,不像在 class 中撰寫 style 的時候會統一列出的樣式方便查看 - 這點真的就比較難處理了…這邊會推薦點開 devTool 中的 .cls 標籤來瀏覽該 DOM 元素套用的 class 有哪些。 ## 推薦以下資源來協助 TailwindCSS 的開發: - [Tailwind CSS 官網](https://tailwindcss.com/) - 在官網 cmd + k 輸入想查找的屬性,就可以取得對應的 className - cmd + k 輸入 `translatex` 會出現 `translate-x-0` 等相關的 class 文件頁面 - [Tailwind cheat sheet](https://nerdcave.com/tailwind-cheat-sheet) - 將所有 class 列出來方便查找,但最終還是以官網文件為主 - [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - VS Code 套件,會提示 className 的樣式 ## TailwindCSS 的使用說明 ### 常用的寫法介紹 - 顏色套用:[色彩表](https://tailwindcss.com/docs/customizing-colors) | 原生 CSS | TailwindCSS | | -------- | -------- | | color: red; | text-red-400 | | background-color: blue; | bg-blue-300 | - 有上下左右設定的樣式: | 原生 CSS | TailwindCSS | | -------- | -------- | | margin-top: 20px;|mt-[20px] | | padding-left: 13px;| pl-[13px]| | right: 30%; |right-[30%] | | border-bottom-width: 13px; | border-b-[13px] | | padding: 30px 10px; | p-y-[30px] p-x-[10px] | - hover, active, focus: [官方文件](https://tailwindcss.com/docs/hover-focus-and-other-states#hover-focus-and-active) | 原生 CSS | TailwindCSS | | -------- | -------- | | .btn:hover {color: red;} | hover:text-red-300 | | .btn:active {background-color: green;} | active:bg-green-500 | | .btn:focus {outline-color: yellow;} | focus:outline-yellow-200 | - first-child, last-child: [官方文件](https://tailwindcss.com/docs/hover-focus-and-other-states#first-last-odd-and-even) | 原生 CSS | TailwindCSS | | -------- | -------- | | li:first-child{ color: red; } | first:text-red-200 | | li:last-child{ color: green; } | last:text-green-700 | - media-query: [官方文件](https://tailwindcss.com/docs/responsive-design) tailwind 中的 break point 是採用 [mobile-first](https://tailwindcss.com/docs/responsive-design#working-mobile-first "‌") 的方式,media-query 是以 `min-screen` 去做的,拿 `md:@media (min-width: 768px)`來說的話,是當螢幕寬度大於 md 尺寸的時候會套用該樣式,不是小於,與使用 `@media (max-width: 768px)` 的方式相反 ```css /* css */ .container { width: 100%; } @media (min-width: 768px) { .container { width: 50%; } } ``` ```html // tailwind <div className='w-full md:w-1/2'>child</div> ``` ### [tailwind.config.js](https://tailwindcss.com/docs/configuration):專案的 Design guide line 在 tailwind.config.js 中,我們可以 - [content](https://tailwindcss.com/docs/content-configuration):設定要使用 TailwindCSS 的檔案路徑,如果在檔案中發現 TailwindCSS 的 class 都沒有作用的話,可以檢查一下 content 中有沒有涵蓋你的檔案。 - [theme](https://tailwindcss.com/docs/theme):設定主題,以下方的 color 與 bg-image 的設定為例,官方文件中都有對每個屬性該如何在 tailwind.config.js 做延伸有說明:[color](https://tailwindcss.com/docs/text-color#customizing-your-theme), [bg-image](https://tailwindcss.com/docs/background-image#customizing-your-theme),要注意的是如果設定不是在 extend 中追加的話,是會將原本預設的設定給覆蓋過去的。 - [plugins](https://tailwindcss.com/docs/plugins):Tailwind 官方提供了許多方便的額外插件使用,重置表單元素樣式的 [tailwindcss-forms](https://github.com/tailwindlabs/tailwindcss-forms)、用來設定元素等比例縮放的 [tailwindcss-aspect-ratio](https://github.com/tailwindlabs/tailwindcss-aspect-ratio)、將超出行數文字隱藏的 [tailwindcss-line-clamp](https://github.com/tailwindlabs/tailwindcss-line-clamp)...等等,妥善運用的話可以省去許多撰寫額外樣式的工。 ```javascript= // tailwind.config.js module.exports = { // 記得檢查要使用 Tailwind 的檔案是否涵蓋在這之中了 content: [ './pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}', ], them: { // 在 extend 中設定的話表示這是追加的 // 把 colors 拉到 extend 以外的話 // 就會變成只有你設定的這些 colors 能用 extend: { colors: { primary: { warn: '#警告色的色碼' } }, backgroundImage: { 'main-banner': 'url(\'圖片路徑放這邊\')', 'sub-banner': 'url(\'../assets/img/sub-banner.png\')', } }, plugins: [], } } ``` ```htmlmixed= // 一般的顏色套用 <p className='text-red-500'>text</p> // 想要在專案中套用遵循設計 guide line 的顏色名稱 <p className='text-primary-warn'>text</p> // 一般的背景色套用 <div className='bg-blue-400'>...</div> // 套用自訂的背景圖片 <div className='bg-main-banner'>...</div> ``` - 除了擴充設定檔之外,tailwind 有提供另一種方式來使用預設沒有的樣式,以文字大小為例,預設是沒有 font-size 27px 這種的,這時候我們可以透過 `text-[27px]` 來套用自定義的樣式,同樣地在每個樣式的說明文件也有對 arbitrary values 的說明:[text arbitrary values](https://tailwindcss.com/docs/font-size#arbitrary-values "‌") ```htmlmixed= // 一般的文字大小套用 // text-base 是 1rem,也就是 16px <p className='text-base'>text</p> // 套用自定義的文字大小 <p className='text-[27px]'>text</p> // 其他樣式的預設 <div className='w-20 mt-8 translate-x-3.5 rounded-full'>...</div> // 上述樣式的自定義寫法 <div className='w-[13px] mt-[7%] translate-x-[14vw] rounded-[80%]'>...</div> ``` ## [clsx](https://www.npmjs.com/package/clsx):讓 className 撰寫變得更加彈性的套件 clsx 讓我們在 react 中撰寫 className 的時候更為方便與彈性 使用的時候是 1. 將原本的 `className='class-name'` 中傳入字串的單引號改為傳入變數的大括號`{}` 2. 在裡面呼叫 `clsx()` 3. 透過 `clsx()` 這個 function 將裡面帶入的變數、字串等,組合成一個字串回傳給 className ```htmlmixed= // 使用 clsx 前 <span className='text-base font-lg'> 這邊是文字 </span> // 替換成 clsx 的話 <span className={clsx('text-base font-lg')}> 這邊是文字 </span> ``` - 透過分段的方式來將一長串的 className 變的更為好讀 ```jsx= <div className={clsx( 'relative h-[240px] w-[240px] p-[10px]', 'rounded-3xl bg-white/30', )} > text </div> ``` - 傳入變數 ```jsx= // 變數 const dataList = [ { classList: 'w-[612px] h-[520px]', text: 'text01' }, { classList: 'w-[412px] h-[770px]', text: 'text02' } ] // JSX <ul> { dataList.map((item, idx) => ( <li className={clsx( item.classList, 'relative pl-8', 'flex flex-row items-center space-x-4', 'bg-cover bg-center bg-no-repeat', )} key={idx} >{item.text}</li> )) } </ul> ``` - 可以傳入 css-module 的 class ```jsx= import styles from './styles/Main.modules.scss' <div className={clsx( styles.mainTitle, 'flex flex-col' )} > text </div> ``` - 透過條件判斷來決定要使用的 class ```jsx= <div className={clsx( {'relative': true}, {'relative': (1-2) !== 0}, {'relative': ('apple' === 'apple') && (3 > 0)}, ('apple' === 'apple') && 'relative', isOpen ? 'block' : 'hidden', 'text-base text-blue-400' )}>text</div> ``` ‌