相同的原由 & 前言
如果你沒有聽説過 tailwindcss 或者 unocss,請先
return
先去了解一下😝。
- 開發上:可能為你甚至你們的前端團隊節省很多寫樣式的時間,也能讓你或者你們的項目開發體驗有很大提升
- 生產上:你們的項目打出來的包體積中的樣式代碼佔比將突然驟降然後趨於不變。
書接上回
之前我寫過一篇文章給我一個你不用tailwindcss的理由!,極力推薦使用 tailwindcss 來提升開發效率和體驗,尤其是樣式代碼的體驗會有質的提升。當然樣式代碼打包體積的減少也可以起到優化我們整體前端項目的作用。但是為什麼有這篇文章了呢?因為託尼老師給了我不用 tailwindcss 的理由,無法拒絕的理由,就是我們今天的主角 UnoCSS
為什麼我換到了UnoCSS
tailwindcss 和 UnoCSS 都是原子化CSS模式實現的一種,為什麼現在我更推薦 UnoCSS ,接下來就講一下 UnoCSS 的殺手級亮點:
極致性能
這裏我借用託尼老師的話:
No parsing, no AST, no scanning, it's INSTANT (5x faster than Windi CSS or Tailwind JIT).
跳過解析,不使用 AST
從內部實現上看,Tailwind 依賴於 PostCSS 的 AST 進行修改。考慮到在開發過程中,這些工具 CSS 的並不經常變化,UnoCSS 通過非常高效的字符串拼接來直接生成對應的 CSS 而非引入整個編譯過程。同時,UnoCSS 對類名和生成的 CSS 字符串進行了緩存,當再次遇到相同的實用工具類時,它可以繞過整個匹配和生成的過程。
現在説是比 tailwindcss 快5倍,其實當年可是比 tailwindcss JIT 模式快200倍的存在,後面 tailwindcss 應該是做了大量的優化工作,才讓託尼老師改口稱5倍快了😜。
完全可定製,不是一個框架,而是引擎
相比於 tailwindcss 必須把原子類寫到 class 裏面, UnoCSS 提供了更多可選方案,並且兼容多種風格的原子類框架,除了 tailwindcss ,同樣支持 Bootstrap, Tachyons,Windi CSS
屬性化模式
這個模式也是由 Windi CSS 啓發而來:
Attributify preset
// install
pnpm add -D @unocss/preset-attributify
// uno.config.ts
import { defineConfig } from 'unocss'
import presetAttributify from '@unocss/preset-attributify'
export default defineConfig({
presets: [
presetAttributify({ /* preset options */ }),
// ...
],
})
🌰:
<div class="m-2 rounded text-teal-400" />
<!-- 現在你可以這麼寫: -->
<div m-2 rounded text-teal-400 />
前綴組,解決繁瑣的多次寫前綴的情況
Variant group transformer
// install
pnpm add -D @unocss/transformer-variant-group
// uno.config.ts
import { defineConfig } from 'unocss'
import transformerVariantGroup from '@unocss/transformer-variant-group'
export default defineConfig({
// ...
transformers: [
transformerVariantGroup(),
],
})
比如我們在設置字體的時候常常會設置顏色、大小,或者在 hover 的情況下改動多個屬性我們就可以這樣🌰:
<div class="hover:bg-gray-400 hover:font-medium font-light font-mono"/>
<!-- 簡化之後: -->
<div class="hover:(bg-gray-400 font-medium) font-(light mono)"/>
快捷方式和指令
Directives transformer
// install
pnpm add -D @unocss/transformer-directives
// uno.config.ts
import { defineConfig } from 'unocss'
import transformerDirectives from '@unocss/transformer-directives'
export default defineConfig({
// ...
transformers: [
transformerDirectives(),
],
})
用過 tailwindcss 的同學都知道, tailwindcss 有指令系統,其中的 @layer components 指令可以把通用的樣式 layer 到一個類上:
@layer components {
.btn-blue {
@apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded;
}
}
UnoCSS 有類似的更好用快捷方式來快捷實現這個功能:
shortcuts: [
// you could still have object style
{
btn: 'py-2 px-4 font-semibold rounded-lg shadow-md',
},
// dynamic shortcuts
[/^btn-(.*)$/, ([, c]) => `bg-${c}-400 text-${c}-100 py-2 px-4 rounded-lg`],
]
另外還有一個使用很頻繁的指令 @apply ,這個指令在以下兩種情況下比較合適使用:
- 有一個樣式很多,很複雜的元素,直接寫到標籤裏面會影響代碼可讀性
- 同樣的樣式應用到很多元素上
🌰:
<div text-lg text-pink-400 font-bold border-1 border-gray border-dashed rounded flex flex-warp items-center justify-evenly>
我的樣式很複雜的
</div>
<button text-green-500 rounded hover:text-lg shadow-md>查詢</button>
<button text-green-500 rounded hover:text-lg shadow-md>提交</button>
<button text-green-500 rounded hover:text-lg shadow-md>取消</button>
就可以這麼優化:
<div class="complex-node">
我的樣式很複雜的
</div>
<button class="btn">查詢</button>
<button class="btn">提交</button>
<button class="btn">取消</button>
<style>
.complex-node {
@apply text-lg text-pink-400 font-bold border-1 border-gray border-dashed rounded flex flex-warp items-center justify-evenly;
}
.btn {
@apply text-green-500 rounded hover:text-lg shadow-md;
}
</style>
構建合併多個原子類到一個類
Compile class transformer
// install
pnpm add -D @unocss/transformer-compile-class
// uno.config.ts
import { defineConfig } from 'unocss'
import transformerCompileClass from '@unocss/transformer-compile-class'
export default defineConfig({
// ...
transformers: [
transformerCompileClass(),
],
})
這個特性一般比較少用,也可以看下是什麼作用,通過 :uno: 標記,可以最終編譯為一個類:
<div class=":uno: text-center sm:text-left">
<div class=":uno: text-sm font-bold hover:text-red"/>
</div>
最終編譯的結果:
<div class="uno-qlmcrp">
<div class="uno-0qw2gr"/>
</div>
.uno-qlmcrp {
text-align: center;
}
.uno-0qw2gr {
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 700;
}
.uno-0qw2gr:hover {
--un-text-opacity: 1;
color: rgba(248, 113, 113, var(--un-text-opacity));
}
@media (min-width: 640px) {
.uno-qlmcrp {
text-align: left;
}
}
檢查器,可以詳細的預覽我們項目中的所有原子類
我們在啓動開發服務器之後,可以直接訪問localhost:5173/__unocss 就會看到這個畫面:
直接就可以看到所有的原子類,具體某個組件中的原子類,打包後的體積等信息。
你的項目太老也想用?安排!
有些同學可能還在維護很老的前端項目,但是也想用上 UnoCSS 來提升開發體驗, UnoCSS 提供了 CDN 版本,在前端的入口 index.html 文件中添加一行代碼就可以支持,並且還支持配置💪:
<script src="https://cdn.jsdelivr.net/npm/@unocss/runtime"></script>
<script>
// pass unocss options
window.__unocss = {
rules: [
// custom rules...
],
presets: [
// custom presets...
],
// ...
}
</script>
VS Code 插件當然也有
UnoCSS - Visual Studio Marketplace
你以為到這裏就結束了?
再來給你看個好東西!
Icons preset (unocss.dev)
可以在 UnoCSS 中輕鬆集成純 CSS 圖標,可以在這裏查看所有可用圖標,想用哪種就可以安裝對應的包即可:
// uno.config.ts
import { defineConfig } from 'unocss'
import presetIcons from '@unocss/preset-icons'
export default defineConfig({
presets: [
presetIcons({ /* options */ }),
// ...other presets
],
})
沒有你們設計中意的圖標,UI 自己設計的圖標也可以輕鬆集成,首先安裝工具:
pnpm install -D @iconify/utils
然後把設計老師給的 svg 圖標文件放到一個文件夾,我這裏就放到src/assets/svg中,然後想一個圖標名稱,這裏就叫 icon 吧
// unocss.config.ts
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'
import {
defineConfig,
presetAttributify,
presetIcons,
presetUno,
} from 'unocss'
export default defineConfig({
presets: [
presetUno(),
presetAttributify(),
presetIcons({
collections: {
icon: FileSystemIconLoader(
'./src/assets/svg',
svg => svg.replace(/#FFF/, 'currentColor'),
),
},
scale: 1.5,
warn: true,
}),
],
})
可以看到配置中 collections 裏面有一個 icon 對象,這個名稱就對應了我們剛才説的 icon 名稱,對應的是一個 FileSystemIconLoader 方法,方法的第一個參數是你的圖標在項目中的路徑,我這裏就是 ./src/assets/svg,按照相對路徑就可以,也可以通過第二個參數做一些特殊預處理操作,具體可以看這個文檔,這樣配置完成之後,我們就可以在項目使用了。
比如我在src/assets/svg文件夾中放了一個 cancel.svg 的取消圖標,我在頁面上使用就可以這樣寫:
<div text-lg text-red inline-block i-icon:cancel />
其中的 i-icon 就是我們前面配置的自定義圖標集的名稱,冒號後面跟的就是你的 svg 圖標的名稱,可以通過樣式改變圖標的大小和顏色,是不是很酷😎。
豐富、靈活、開放的預設生態
UnoCSS 提供了豐富的預設,以支持不同風格體系的前端開發者,生態很完善,在 UnoCSS 發佈之後我在很多項目中都應用實踐過,基本可以覆蓋所有樣式場景。
總結
原子化CSS 的理念早已不是新鮮事物了, tailwindcss 、UnoCSS 這類解決方案把這個理念有了一個很好的實踐和實現,可以真正的提升開發者體驗和編碼效率,都是很值得一學的技術。最後,有用請點贊,喜歡請關注,我是Senar,我們下一篇再見~