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