ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

UnoCSS preset-icons 深度指南:把任意 Iconify 图标变成 Pure CSS 图标

2026/9/13 15:11:25 拓冰建站 浏览量
UnoCSS preset-icons 深度指南:把任意 Iconify 图标变成 Pure CSS 图标 UnoCSS preset-icons 深度指南把任意 Iconify 图标变成 Pure CSS 图标【免费下载链接】unocssThe instant on-demand atomic CSS engine.项目地址: https://gitcode.com/GitHub_Trending/un/unocssUnoCSS 的 preset-icons 预置让开发者无需图标字体、无需图标组件库仅凭一个 class 名如i-mdi-alarm就能在页面中渲染出自 Iconify 生态的任意 SVG 图标。本文基于仓库中的官方文档 docs/presets/icons.md 展开并结合 packages-presets/preset-icons/src/core.ts 等源码讲清它的命名约定、安装配置、渲染模式控制、图标集加载策略浏览器 / Node.js / CDN / 自定义 Loader、三层定制机制transform/customize/iconCustomizer、icon()CSS 指令以及全部配置项帮助你在实际项目中直接复制可用的配置。一、Pure CSS 图标的原理mask 与 background 两种渲染模式preset-icons 生成的并不是图片文件而是一段带 SVG Data URI 的 CSS。每个图标最终都是一个类选择器样式由两种模式之一产生源码见 core.tsmask 模式利用 CSSmask属性图标作为遮罩、颜色来自background-color: currentColor因此图标可以随文字颜色自由变色适合单色图标bg 模式直接以 SVG Data URI 作为background背景图颜色是静态的SVG 里画了什么颜色就是什么颜色适合彩色图标。在auto模式默认下preset 会对解析出的 SVG 做判断如果 SVG 源码中包含currentColor关键字则使用mask否则使用bg见 core.ts。这一点解释了为什么彩色图标如vscode-icons:file-type-light-pnpm默认走bg模式。两种模式生成的 CSS 形如mask 模式摘自源码.i-mdi-alarm { --un-icon: url(data:image/svgxml;utf8,%3Csvg ...%3E); -webkit-mask: var(--un-icon) no-repeat; mask: var(--un-icon) no-repeat; -webkit-mask-size: 100% 100%; mask-size: 100% 100%; background-color: currentColor; color: inherit; /* 兼容 Safari */ width: 1em; height: 1em; }bg 模式则输出background: url(...) no-repeat; background-size: 100% 100%; background-color: transparent;。尺寸默认取${scale}${unit ?? em}作为兜底见 core.ts因此图标会跟随font-size缩放——这也是text-3xl能让图标变大的原因。二、命名约定collection-icon与collection:icon使用图标只需遵循以下两条命名约定prefixcollection-iconprefixcollection:icon示例来自官方文档!-- 来自 Phosphor 图标集的锚点图标 -- div classi-ph-anchor-simple-thin / !-- 来自 Material Design Icons 的橙色闹钟 -- div classi-mdi-alarm text-orange-400 / !-- 大号 Vue Logo -- div classi-logos-vue text-3xl / !-- 亮色模式显示太阳、暗色模式显示月亮Carbon -- button classi-carbon-sun dark:i-carbon-moon / !-- 悬停时切换表情的 Twemoji -- div classi-twemoji-grinning-face-with-smiling-eyes hover:i-twemoji-face-with-tears-of-joy /从源码看core.ts图标规则的正则是一条/^([\w:-])(?:\?(mask|bg|auto))?$/即主体允许: - ? 字母数字下划线并可选携带?mask/?bg/?auto后缀下一节详述。解析逻辑在parseIconWithLoadercore.ts中若主体包含:按collection:name直接切分若不含:则按-切分并从最长 3 段开始逐级缩短尝试匹配内置集合名COLLECTION_NAME_PARTS_MAX 3。例如fa-solid是集合、ph是集合、mdi是集合于是i-mdi-alarm会被解析为集合mdi 图标alarm。这就是为什么以i-为前缀的连字符写法无需冒号也能工作内置的合法集合名列表由 collections.ts 提供覆盖了mdi、carbon、lucide、tabler、ph、logos、twemoji等数百个iconify-json集合。新发布的、不在该列表中的集合需要配合iconifyCollectionsNames选项声明见第七节。所有可用图标集可在线检索Iconify / Icônes 站点文档中也给出了完整列表的参考入口。三、安装与基础配置3.1 安装除 preset 本体外还需要按iconify-json/*模式在devDependencies中安装对应的图标集例如iconify-json/mdiMaterial Design Icons、iconify-json/tablerTabler# pnpm pnpm add -D unocss/preset-icons iconify-json/[the-collection-you-want] # yarn yarn add -D unocss/preset-icons iconify-json/[the-collection-you-want] # npm npm install -D unocss/preset-icons iconify-json/[the-collection-you-want] # bun bun add -D unocss/preset-icons iconify-json/[the-collection-you-want]如果想一次性安装 Iconify 上全部图标集约 130MBpnpm add -D iconify/json # 或 yarn / npm / bun install -D iconify/json3.2 在 UnoCSS 配置中启用// uno.config.ts import presetIcons from unocss/preset-icons import { defineConfig } from unocss export default defineConfig({ presets: [ presetIcons({ /* options */ }), // ...other presets ], })两个实用提示与文档一致该 preset 已被打包进unocss包可以直接import { presetIcons } from unocss无需单独安装它也可以脱离 UnoCSS 体系单独使用作为现有 UI 框架的补充来提供 Pure CSS 图标。3.3 Node.js 环境的自动发现在 Node.js 环境下无需手动注册任何集合preset 会自动探测并加载node_modules中已安装的 iconify 数据集。源码上这由 index.ts 中的createNodeLoader实现——它动态import(iconify/utils/lib/loader/node-loader)得到loadNodeIcon与 CDN Loader、loadIcon一起经combineLoaders链式组合任一 Loader 命中即返回见 core.ts。另外 preset 以enforce: pre注册、并声明iconslayer优先级-30保证图标类规则在正确的层中输出见 core.ts。3.4 Extra Properties为图标注入默认 CSS通过extraProperties可以给所有图标附加默认样式例如让图标默认内联显示presetIcons({ extraProperties: { display: inline-block, vertical-align: middle, // ... }, })从源码看extraProperties最终作为 Iconify 的additionalProps注入core.ts会合并进每条图标的 CSS 对象中。四、渲染模式控制mode选项与?bg/?mask覆盖mode选项类型为mask | bg | auto默认automask单色图标用mask属性 背景色着色bg以背景图渲染颜色静态auto按图标的currentColor特征逐图标智能判定。当自动判定不符合预期时可以在单个 class 上用后缀显式覆盖文档中的例子是彩色 pnpm 文件图标?bg—— 强制渲染为背景图?mask—— 强制渲染为 mask 图从而绕过图标自带颜色。!-- 默认 bg 模式显示彩色 -- div classi-vscode-icons:file-type-light-pnpm / !-- 强制 mask 模式跟随 text-red-300 变色 -- div classi-vscode-icons:file-type-light-pnpm?mask text-red-300 /仓库测试 test/preset-icons.test.ts 中也专门覆盖了i-carbon-sun?bg、dark:i-carbon-moon?auto这类变体输出快照见 test/assets/output/preset-icons.css可用于验证你本地生成的 CSS 与预期一致。五、图标集的加载策略Browser vs Node.jscollections选项的类型为Recordstring, (() AwaitableIconifyJSON) | undefined | CustomIconLoader | InlineCollection。Node.js 下它通常无需配置自动发现已安装的集但在浏览器环境下它决定了“数据集从哪里来、怎么加载”。5.1 浏览器 Bundler动态 import 按需加载浏览器场景应安装iconify-json/[collection]而不是完整的iconify/json后者文件巨大。使用动态import()后打包器会把每个集合拆成异步 chunk、按需加载import presetIcons from unocss/preset-icons/browser export default defineConfig({ presets: [ presetIcons({ collections: { carbon: () import(iconify-json/carbon/icons.json).then(i i.default), mdi: () import(iconify-json/mdi/icons.json).then(i i.default), logos: () import(iconify-json/logos/icons.json).then(i i.default), }, }), ], })注意此处入口是unocss/preset-icons/browser。该构建入口browser.ts不做 Node 自动发现若配置了cdn与customFetch则使用createCDNFetchLoader(fetcher, cdn)只有cdn则走 CDN Loader否则退回到 Iconify 的loadIcon即使用collections中注册的 Loader。这与package.json中的 exports 映射./browser→dist/browser.mjsbrowser条件 → 同一文件一致。5.2 浏览器 CDNv0.32.10 起支持cdn选项presetIcons({ cdn: https://esm.sh/ })要求 URL 以https://开头、以/结尾官方推荐https://esm.sh/或https://cdn.skypack.dev/。其内部实现core.ts会拼接${cdnBase}iconify-json/collection/icons.json拉取整个集合并用Map做进程级缓存拉回后对图标名做归一化尝试——原始名、camelCase 转 kebab-case、字母后数字前插连字符三种变体依次检索默认 fetcher 是 ofetch也可通过customFetch替换。注意CDN 方式仅对内置集合列表中的名称生效fetchCollection会先校验icons.includes(name)自定义集合名不会走 CDN 拉取。5.3 浏览器 自定义集合InlineCollection/CustomIconLoader可以直接把 SVG 字符串内联为集合也可以混用动态 importpresetIcons({ collections: { custom: { circle: svg viewBox0 0 120 120circle cx60 cy60 r50/circle/svg, /* ... */ }, carbon: () import(iconify-json/carbon/icons.json).then(i i.default as any), /* ... */ }, })之后即可在模板中写span classi-custom:circle/span。更复杂的场景可实现 Iconify 的CustomIconLoader接口。5.4 Node.jsFileSystemIconLoader从文件系统加载Node.js 下 preset 会自动搜索已安装的 iconify 数据集无需注册。若要加载自有图标需额外安装iconify/utilsdev dependency典型配置// unocss.config.ts import fs from node:fs/promises // loader helpers import { FileSystemIconLoader } from iconify/utils/lib/loader/node-loaders import { defineConfig, presetIcons } from unocss export default defineConfig({ presets: [ presetIcons({ collections: { // key as the collection name my-icons: { account: svg!-- ... --/svg, // load your custom icon lazily settings: () fs.readFile(./path/to/my-icon.svg, utf-8), /* ... */ }, my-other-icons: async (iconName) { // your custom loader here. Do whatever you want. // for example, fetch from a remote server: return await fetch(https://example.com/icons/${iconName}.svg).then(res res.text()) }, // a helper to load icons from the file system // files under ./assets/icons with .svg extension will be loaded as its file name // you can also provide a transform callback to change each icon (optional) my-yet-other-icons: FileSystemIconLoader( ./assets/icons, svg svg.replace(/#fff/, currentColor) ), }, }), ], })5.5 Node.jscreateExternalPackageIconLoader加载第三方图标包自iconify/utils v2.1.20起可用createExternalPackageIconLoader从其他作者发布的 npm 包中加载图标。前提是该包内包含IconifyJSON格式的icons.json文件可用 Iconify Tools 导出import { createExternalPackageIconLoader } from iconify/utils/lib/loader/external-pkg import { defineConfig, presetIcons } from unocss export default defineConfig({ presets: [ presetIcons({ collections: createExternalPackageIconLoader(an-awesome-collection) }), ], })也可以与FileSystemIconLoader等其他 Loader 自由组合import { createExternalPackageIconLoader } from iconify/utils/lib/loader/external-pkg import { defineConfig, presetIcons } from unocss import { FileSystemIconLoader } from unplugin-icons/loaders export default defineConfig({ presets: [ presetIcons({ collections: { ...createExternalPackageIconLoader(other-awesome-collection), ...createExternalPackageIconLoader(my-awesome-collections/some-collection), ...createExternalPackageIconLoader(my-awesome-collections/some-other-collection), my-yet-other-icons: FileSystemIconLoader( ./assets/icons, svg svg.replace(/^svg /, svg fillcurrentColor ) ), }, }), ], })六、图标定制transform、customize与iconCustomizercustomizations选项类型为OmitIconCustomizations, additionalProps | trimCustomSvg完整定义见 types.ts提供三层定制函数。对每个加载到的图标按以下顺序应用若提供了transform且当前使用的是自定义图标集先对原始svg字符串执行transformiconify官方集合被排除在外不会改写其 SVG若提供了customize以其修改默认定制值若提供了iconCustomizer在上一步结果之上继续修改。6.1 全局 SVG 变换仅自定义集合例如给自有图标补上currentColorpresetIcons({ customizations: { transform(svg) { return svg.replace(/#fff/, currentColor) }, }, })自0.30.8版本起transform还会收到collection与icon两个参数可按集合/图标做条件处理presetIcons({ customizations: { transform(svg, collection, icon) { // do not apply fill to this icons on this collection if (collection custom icon my-icon) return svg return svg.replace(/#fff/, currentColor) }, }, })6.2 全局属性定制作用于所有图标presetIcons({ customizations: { customize(props) { props.width 2em props.height 2em return props }, }, })6.3 按集合/图标粒度定制iconCustomizericonCustomizer(collection, icon, props)优先于通用配置且适用于任何来源的图标自定义 Loader、内联集合或iconify官方集合presetIcons({ customizations: { iconCustomizer(collection, icon, props) { // customize all icons in this collection if (collection my-other-icons) { props.width 4em props.height 4em } // customize this icon in this collection if (collection my-icons icon account) { props.width 6em props.height 6em } // customize this iconify icon in this collection if (collection mdi icon account) { props.width 2em props.height 2em } }, }, })测试用例 test/preset-icons.test.ts 验证了两个值得注意的细节iconCustomizer可以把width/height设为var(--icon-size)这类 CSS 变量甚至auto而 preset 内置的unit逻辑只在props.width/height未设置时才回填${scale}${unit}core.ts因此显式定制的值不会被覆盖。此外自定义 SVG 会经过trimCustomSvg处理测试 svg prologue clearedtest/preset-icons.test.ts确认了 XML 声明、DOCTYPE 等 prologue 会从 Data URI 前缀中被清除保证data:image/svgxml;utf8,%3Csvg的干净输出。七、icon()CSS 指令你还可以在 CSS 中通过icon()指令获取图标的 Data URI.icon { background-image: icon(i-carbon-sun); }注意icon()指令依赖unocss/preset-icons并复用其配置必须先引入该 preset。更完整的指令用法见 Directives 文档。八、完整选项速查以下选项汇总自官方文档默认值与 types.ts 及 core.ts 中的实现一致选项类型默认值说明scalenumber1相对于当前字号1em的缩放倍数modemask \| bg \| autoauto生成 CSS 图标的渲染模式auto按 SVG 是否含currentColor逐图标判定prefixstring \| string[]i-匹配图标规则的类名前缀extraPropertiesRecordstring, string{}附加到生成 CSS 上的额外属性如display: inline-blockwarnbooleanfalse匹配到不存在的图标时发出警告实现上会在 ESLint 环境下静默见 core.tsiconifyCollectionsNamesstring[]undefined补充声明未列入内置列表的新iconify-json集合注意外部自定义集合不能用它应使用FileSystemIconLoader或createExternalPackageIconLoadercollectionsRecordstring, (() AwaitableIconifyJSON) \| undefined \| CustomIconLoader \| InlineCollectionundefinedNode.js 下自动发现已安装数据集浏览器下用其提供数据集与自定义加载机制layerstringicons图标规则所在 layercustomizationsOmitIconCustomizations, additionalProps \| trimCustomSvgundefinedtransform/customize/iconCustomizer三层定制autoInstallbooleanfalse检测到图标使用且缺少对应包时自动安装图标源包仅 Node.js 环境有效浏览器下被忽略unitstringem图标尺寸单位如rem与scale组合决定默认宽高cdnstringundefined从 CDN 加载图标须以https://开头、/结尾推荐https://esm.sh/、https://cdn.skypack.dev/v0.32.10 起支持customFetch(url: string) Promiseanyundefined自定义 fetch 函数替代默认的ofetch用于提供图标数据processor(cssObject: CSSObject, meta: RequiredIconMeta) voidundefined在 CSS 对象序列化前的钩子可对cssObject做最后加工其中IconMeta结构为interface IconMeta { collection: string icon: string svg: string mode?: IconsOptions[mode] }processor的一个真实用例见 test/preset-icons.test.ts在bg模式下删掉width/height让图标尺寸完全交给外层容器控制对应输出快照在 test/assets/output/preset-icons-propsProcessor.css。九、自定义图标集清理与无障碍9.1 自定义图标集的 Cleanup使用自定义图标集时建议参照 Iconify 对图标集做的清理流程Iconify Tools 提供了完整工具链例如统一替换#fff为currentColor、移除多余属性使图标更适配 mask 着色模式官方也维护了基于本 preset 的 Vue 3 演示项目可供参考Iconify Tools 仓库中的 unocss 示例。9.2 Accessibility Concerns图标对屏幕阅读器用户是不可见的需要为它们提供替代文本!-- 有意义的图标提供 aria-label -- a href/profile aria-labelProfile classi-ph:user-duotone/a纯装饰性图标则应从可访问性树中隐藏a href/profile span aria-hiddentrue classi-ph:user-duotone/span My Profile /aCSS 图标在行为上类似 icon font因此图标字体的无障碍技巧同样适用。若需要“视觉隐藏但对读屏可用”的元素可参考 Wind3 preset 提供的sr-only工具类。十、小结preset-icons 的设计可以概括为三句话命名即取用i-collection-icon或i-collection:icon解析规则见 core.ts、模式自动判定、可按需覆盖auto/?bg/?mask、数据源可插拔Node 自动发现、Bundler 动态 import、CDN、FileSystemIconLoader、createExternalPackageIconLoader与内联集合任意组合。配合extraProperties、unit/scale与transform/customize/iconCustomizer三层定制你可以在不引入任何图标组件的前提下把 Iconify 生态的全部图标资产无缝接入 UnoCSS 流水线。来源致谢该 preset 的雏形来自社区对 unplugin-icons 的 issue 讨论并基于相关 PR 的工作演化而来详见 docs/presets/icons.md 的 Credits 部分。【免费下载链接】unocssThe instant on-demand atomic CSS engine.项目地址: https://gitcode.com/GitHub_Trending/un/unocss创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考