在 UnoCSS 生态中,颜色系统一直以预设色板(如 rose-500、blue-600)为核心,配合 theme.colors 扩展自定义色板。但实际业务场景往往更复杂:
- 设计系统需要精确到非标准色阶(如
445、187),官方固定步长(50,100,...950)无法覆盖; - 需要为组件定义局部颜色变量,又不希望污染全局或手写 CSS 变量;
- 暗黑模式下,同一个语义色(如
primary)需要映射不同色相,且色阶方向需要反转(浅色模式用亮色,暗色模式用暗色); - 运行时换色需求(多主题切换)往往需要重新构建整套样式,代价高昂。
Magicolor 预设正是为解决这些问题而生 ------ 它在不替换 UnoCSS 原有颜色系统的前提下,增加了一层 mc- 魔法颜色能力,提供任意数字色阶、局部颜色定义、全局语义别名和运行时更新等特性。
源码链接 :github.com/nixwai/unoc...
📦 快速开始
安装
使用 npm、pnpm 或 bun 安装预设:
bash
# npm
npm install -D unocss-preset-magicolor
# pnpm
pnpm add -D unocss-preset-magicolor
# bun
bun add -d unocss-preset-magicolor
使用本预设前,请先按照官方 UnoCSS 集成指南 安装并配置 UnoCSS。保留项目中已有的 UnoCSS 预设,然后添加 presetMagicolor()。
配置
把预设加入 UnoCSS 配置:
ts
// uno.config.ts
import { defineConfig, presetWind4 } from 'unocss';
import { presetMagicolor } from 'unocss-preset-magicolor';
export default defineConfig({
presets: [
presetWind4(),
presetMagicolor(),
],
});
🎨 基本使用与颜色变量定义
直接使用任意色阶
直接在模板中使用 mc- 颜色工具类:
html
<button class="rounded px-4 py-2 bg-mc-rose-445 c-white hover:bg-mc-rose-620">
Magic color
</button>
不同于 rose-500 这类固定色阶,Magicolor 支持任意数字色阶:
html
<div class="bg-mc-rose-445 c-mc-blue-187 border border-mc-neutral-733">
Arbitrary depth colors
</div>
色阶颜色会从当前 UnoCSS 主题色板,或由 magic-color 生成的 50、100、200...950 色板中解析,然后输出为 oklch(...) 自定义属性。预设只会为扫描到的颜色名和色阶生成变量,未使用的变量不会输出。
颜色来源多样性
Magicolor 工具类可以读取多种颜色来源。
UnoCSS 主题颜色 :UnoCSS 内置颜色和 theme.colors 中的自定义颜色都可以直接使用:
ts
// uno.config.ts
export default defineConfig({
presets: [presetWind4(), presetMagicolor()],
theme: {
colors: {
grape: '#679512',
wine: { red: '#9c1d1e' },
},
},
});
html
<button class="border border-mc-wine-red-575 bg-mc-rose-445 px-8 py-4">
<span class="c-mc-grape-160">Hello World!</span>
</button>
任意 CSS 颜色:使用 UnoCSS 任意值语法可以书写一次性颜色:
html
<div class="bg-mc-[rgb(12_22_33)]-220 c-mc-[#789411]-430">
Arbitrary magic color
</div>
全局语义别名 :对于稳定的语义色,例如 primary、brand 或 surface,可以使用 presetMagicolor({ colors }) 定义全局别名:
ts
// uno.config.ts
import { defineConfig, presetWind4 } from 'unocss';
import { presetMagicolor } from 'unocss-preset-magicolor';
export default defineConfig({
presets: [
presetWind4({ dark: 'class' }),
presetMagicolor({
colors: {
primary: { color: 'rose', lightnessReverse: true },
brand: '#4f7bff',
},
dark: {
primary: 'blue',
brand: '#8ab4ff',
},
}),
],
});
html
<button class="bg-mc-primary-457 c-white ring ring-mc-brand-630 hover:bg-mc-primary-620">
Semantic color
</button>
colors 定义亮色模式别名,dark 定义同名暗色模式别名。当存在 presetWind4 时,Magicolor 会跟随它的暗色模式设置,包括 class、media 和自定义选择器。camelCase 别名也可以通过 kebab-case class 使用,例如 brandPrimary 既可以写成 c-mc-brandPrimary-457,也可以写成 c-mc-brand-primary-457。
局部颜色定义(组件级变量)
使用 mc-<name>_<source> 可以在任意 DOM 元素上声明局部颜色源,而无需在全局主题中定义。例如:
html
<div class="mc-card_[#9c1d1e]">
<button class="bg-mc-card-450 px-8 py-4 shadow-mc-card-620 hover:bg-mc-card-575">
<span class="c-mc-card-610">Card button</span>
</button>
</div>
mc-card_[#9c1d1e]定义了一个名为card的局部颜色源,值为#9c1d1e。- 其后代中的
bg-mc-card-450、c-mc-card-610等工具类,会自动基于该源生成对应色阶变量。 - 颜色源也可以是全局别名、主题颜色或其他任意颜色,甚至可带源色阶(如
mc-badge_rose-620)。
这种局部定义方式让组件样式自包含,适合库开发或微前端场景,同时避免了全局变量的污染。
🌗 暗黑模式下的反向亮度
传统暗黑模式通常通过 dark: 变体单独覆盖颜色,但当语义色在亮暗模式下需要相反亮度倾向时(如亮色模式用深色背景,暗色模式则用浅色背景),逐个写变体显得繁琐。Magicolor 提供了两种优雅的反向亮度机制。
1. 通过预设配置启用反向亮度
为语义别名设置 lightnessReverse: true,使其色阶读取方向自动反转:
ts
presetMagicolor({
colors: {
primary: { color: 'rose', lightnessReverse: true },
},
dark: {
primary: { color: 'blue', lightnessReverse: true },
},
})
- 当
lightnessReverse: true时,mc-primary-50实际读取的是rose色板的950色阶,mc-primary-450读取550,而500保持500(因为 500 是中间值)。 - 这样,在亮色模式下使用浅色(如
bg-mc-primary-50)时,暗色模式会自动变成深色,无需额外编写dark:规则。
2. 使用 mc-lr-* 工具类局部反转
你可以在任意 DOM 子树中临时反转一个或多个颜色的色阶,而不修改全局配置:
html
<!-- 反转 primary 色阶 -->
<section class="mc-lr-primary">
<!-- bg-mc-primary-80 实际读取 primary 色板的 950-80=870 色阶 -->
<button class="bg-mc-primary-80 c-white">Reversed primary</button>
</section>
<!-- 反转当前选区中所有已配置的颜色 -->
<div class="mc-lr">
<!-- 同时反转 primary 和 rose -->
<span class="bg-mc-primary-230 c-mc-rose-400">Both reversed</span>
</div>
mc-lr-primary只反转primary这个颜色名。- 裸写
mc-lr则会反转当前元素及其后代中所有正在使用的颜色名(包括全局别名、主题颜色和局部定义的颜色),非常适合在暗黑模式容器内一键调整整体亮度方向。
3. 与 UnoCSS 暗黑选择器联动
当使用 presetWind4({ dark: 'class' }) 或 dark: 'media' 时,Magicolor 会自动跟随 UnoCSS 的暗黑模式配置。你在 presetMagicolor({ dark: {...} }) 中定义的暗色别名,会在对应的 .dark 类或 @media (prefers-color-scheme: dark) 下生效,覆盖亮色别名。整个切换逻辑纯 CSS 驱动,无需额外 JavaScript,性能极佳。
🔧 兼容性:与 UnoCSS 生态无缝协作
Magicolor 设计之初就强调非侵入式,它不会覆盖或破坏 UnoCSS 原有功能,而是作为增强层存在。
- 所有 UnoCSS 变体 (
hover:、focus:、dark:、group-hover:等)和mc-*工具类完全兼容。 - Shortcuts / Safelist / Attributify 模式 :预设内置了 usage scanner,能正确识别
mc-*类并生成对应变量,无需额外配置。 transparent、currentColor、inherit等特殊颜色关键字会直接透传,不会误生成 magic 变量。- 与
presetWind4或presetUno等主流预设协同工作 :主题色板(theme.colors)会被 Magicolor 自动读取。 - Layer 优先级可控 :默认
mc-*工具类所在的 layer 排序值为-100,原生 UnoCSS 工具类优先级更高。如需提高mc-*优先级,只需在配置中提升该 layer 的排序值即可。