前言
我們大部分切圖崽都用過iconfont的圖標(biāo)方案,就算你沒用過也不要緊,他看起來像這樣子:
<i class="iconfont icon-hello" />
通過class名iconfont
指出這是iconfont圖標(biāo),再通過icon-hello
圖標(biāo)名指示要渲染哪一個圖標(biāo)。你可以通過修改字體的屬性來改變其大小或顏色:
<!-- 特大號字體 -->
<i class="iconfont icon-hello text-xl" />
看起來很好用,是吧?要說缺點(diǎn),那就是對圖標(biāo)處理很麻煩。可以在這里查看 官方文檔,簡單來說,iconfont的圖標(biāo)本質(zhì)上是字體。為了使用iconfont,你首先需要把svg圖標(biāo)上傳到iconfont,然后圖標(biāo)會被iconfont處理加工,最后導(dǎo)出一系列css、js、json、字體等資源,再放到你的項(xiàng)目中經(jīng)過配置后使用。這不僅在處理圖標(biāo)時麻煩,還會占用比較大的資源(字體),甚至還有字體沖突的可能。長期以來,我們都接收了這種方案。畢竟無論怎么麻煩,都比手動在項(xiàng)目里調(diào)整圖片方便得多。
那么有沒有一種可能,能夠像iconfont一樣便利的修改圖標(biāo)大小與顏色,而且還不需要額外的資源消耗,不需要二次加工圖標(biāo)。新增一個圖標(biāo)時,只需要把圖標(biāo)放入項(xiàng)目中,就能拿來即用?
?拿來!
?
UnoCss
首先貼上 unocss 的官網(wǎng)。大家或多或少都聽說過 unocss,知道他是一個“ 類似于tailwindcss的原子化css ”
。然而正如其官網(wǎng)大標(biāo)題所說,unocss實(shí)際上是一個引擎,各種功能以類似插件的形式通過預(yù)設(shè)
實(shí)現(xiàn),原子化css只不過是官方的可選預(yù)設(shè)之一。對于本文所講的圖標(biāo)預(yù)設(shè),如果你不喜歡原子化css,你完全可以只使用圖標(biāo)預(yù)設(shè),而不使用原子化css預(yù)設(shè),這是不沖突的。本文要談的是 unocss 的官方圖標(biāo)預(yù)設(shè):Icons preset,他使用起來像這樣:
(當(dāng)然,你得先在presets里加上這個預(yù)設(shè))
- 安裝你喜歡的圖標(biāo)庫,這里以unocss作者 @antfu 大神最喜歡用的carbon圖標(biāo)集合為例,你可以安裝由iconify提供的圖標(biāo)庫:
pnpm i -D @iconify-json/carbon
<div class="i-carbon-sun text-3xl c-yellow" />
后面的text-3xl
表示3xl字號,c-yellow
表示黃色字體。大功告成!這樣就能渲染出一個太陽圖標(biāo)。
這里就介紹到antfu大佬的另一個開源庫 icones ,這里面的圖標(biāo)都是能直接在npm下載然后使用的。使用前注意開源協(xié)議喔,建議只使用 MIT
和 Apache 2.0
協(xié)議的圖標(biāo)集合。
我們可以查看 @iconify-json/carbon
這個庫里有什么內(nèi)容。很容易發(fā)現(xiàn)里面幾乎全是svg —— 請看里面的.json文件,svg的內(nèi)容以字符串的形式被儲存在json里。唯一的js代碼只是將圖標(biāo)與其他一些信息導(dǎo)出。那么很容易聯(lián)想到,如果我們以這種格式加入svg圖標(biāo),是否也能像這個庫的圖標(biāo)一樣直接使用呢?
幸運(yùn)的是,UnoCss已經(jīng)提供了這種方案!
使用
讓我們直接看 官方文檔的這個章節(jié),你會震驚的發(fā)現(xiàn),原來文檔里已經(jīng)在一個不起眼的小角落里告訴你怎么使用自己的圖標(biāo)!(大噓)
你首先需要安裝 @iconify/utils
這個庫(基于Node.js)
pnpm i -D @iconify/utils
他使用起來像這樣:
// uno.config.js
import { defineConfig, presetIcons } from 'unocss'
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'
export default defineConfig({
presets: [
presetIcons({
collections: {
my: FileSystemIconLoader('./src/assets/svg')
}
})
]
})
這會讀取 /src/assets/svg
文件夾下所有的.svg文件,并以my
作為前綴,以文件名作為編號。假如我有一個名為sun.svg
的文件,把他放入這個文件夾后,你可以像這樣使用:
<div i-my-sun />
<!-- 大小、顏色 -->
<div i-my-sun text-xl c-yellow />
哇襖!使用圖標(biāo)從未如此酸爽!當(dāng)你需要新增一個圖標(biāo)時,只需要把這個svg放入項(xiàng)目的文件夾中,居然就能直接使用,簡直就是魔法!
當(dāng)然還有個問題,這個FileSystemIconLoader
工具是基于 Node.js
實(shí)現(xiàn)的,我知道在座的各位都是引領(lǐng)潮流的存在,也早就使用過 Bun
等其他運(yùn)行時了。為了在其他運(yùn)行時使用,我們翻看一下這個 函數(shù)的源碼。其實(shí)源碼非常簡單,這是一個高階函數(shù),返回一個接受 name: string
的函數(shù),很容易看出這個就是圖標(biāo)的名字。然后在指定文件夾中搜索圖標(biāo),簡單處理后返回圖標(biāo)內(nèi)容。如此,各位也可以在其他運(yùn)行時中自行實(shí)現(xiàn)。
原理
大家可以閱讀antfu的這篇中文文章 聊聊純 CSS 圖標(biāo) (antfu.me),這個文章中非常全面的講了整個心路歷程。值得一提的是,里面提到通過字體大小修改圖標(biāo)大小這個功能,是基于 em
css單位實(shí)現(xiàn)的。記住這點(diǎn),下面要考。
最佳實(shí)踐
圖標(biāo)分類
在一個項(xiàng)目中可能會使用非常大量的圖標(biāo),由于我們的方案是基于文件路徑的,為了防止起名重復(fù)與維護(hù)困難,我們可以把他們分割在不同的文件夾中,并起不同的前綴,就像這樣:
export default defineConfig({
presets: [
presetIcons({
collections: {
user: FileSystemIconLoader('./src/assets/svg/user'),
dashboard: FileSystemIconLoader('./src/assets/svg/dashboard'),
login: FileSystemIconLoader('./src/assets/svg/login'),
// ...
}
})
]
})
svg轉(zhuǎn)換
我們有時候還會碰到修改字體大小,圖標(biāo)卻沒有變化的情況。這是因?yàn)槊佬g(shù)給的svg寬高單位不對導(dǎo)致的。翻閱 icones
提供的svg圖標(biāo),可以注意到其圖標(biāo)的寬高是統(tǒng)一的 1em
:
<svg width="1em" height="1em" >
</svg>
正如上文所說,必須使用 em
單位才能實(shí)現(xiàn)通過修改字體大小,就可以修改圖標(biāo)大小的功能。FileSystemIconLoader
實(shí)際上接受第二個可選的參數(shù),用于對svg進(jìn)行transform。既然如此,我們可以在這里凹一個正則來將所有的圖標(biāo)寬高改為1em:
FileSystemIconLoader(
'./src/assets/svg',
svg => svg
.replace(/(<svg.*?width=)"(.*?)"/, '$1"1em"')
.replace(/(<svg.*?height=)"(.*?)"/, '$1"1em"'),
)
不用擔(dān)心正則替換的性能問題,因?yàn)樵赾ompile后所有圖標(biāo)都會變成base64。
我們也可能會碰到修改文字/背景顏色,圖標(biāo)顏色卻不跟著變化的情況。這也在antfu的blog中提到,unocss對圖標(biāo)的渲染方式有兩種:
UnoCss利用蒙版實(shí)現(xiàn)了這個功能。而這兩種方式是可以顯式手動指定的:
<!-- 指定為蒙版 -->
<div class="i-my-sun?mask" c-yellow />
<!-- 指定為背景 -->
<div class="i-my-moon?bg" />
svg中使用currentColor
作為顏色的圖標(biāo)通常是單色圖標(biāo)(盡管你還能通過漸變色背景,實(shí)現(xiàn)漸變色的圖標(biāo)),因此通過UnoCss檢查svg中是否存在currentColor
來判斷使用哪種方式渲染,如果存在currentColor
,則默認(rèn)以?mask
渲染。
因此類似寬高,你也可以與美術(shù)約定單色圖標(biāo)使用指定顏色,然后通過正則把這個指定顏色改為 currentColor
,具體不再贅述。
該文章在 2024/11/26 16:59:10 編輯過