从shadcn的更新谈谈前端的颜色
shadcn 最近有个小更新(虽然不少人觉得是大更新,但我个人认为是一个中规中矩的改进)。

这次更新主要是添加了一个主题编辑功能。

其实它做得并没有想象中那么全面,我们可以参考 Ant Design 的主题编辑器。

左边是 design token,右边是对应的组件。在修改完 design token 以后,右边可以实时预览效果。
不过这个功能也算不错,至少能快速处理一些前置的主题设置。
话说回来,这篇文章的主要目的不是点评功能更新,而是想聊聊前端工程师在设计 UI 时,关于颜色处理的一些心得。
其实在设计 UI 时,我最大的苦恼就是选色。如何选出一个合适、不刺眼,且搭配协调的颜色,而不是仅仅追求“好看”?
大家可以想想,其实 UI 组件库已经帮我们处理了很多工作。除去信息架构,我们面临的最核心设计任务往往就是颜色。
我们先来看看 shadcn 是如何处理颜色的。
首先,它会在全局的 CSS 文件里初始化颜色的 CSS 变量(这里就不展示暗黑模式下的变量了,:root 下的就足够了)。
:root { /* --- 基础层:精密科技灰 (Zinc) --- */ /* 背景:极简的冷白,带极其微弱的蓝意 (H=240, C=0.002) */ --background: oklch(0.99 0.002 240); /* 文字:深邃的金属黑,不是纯黑 */ --foreground: oklch(0.15 0.02 240); /* --- 卡片与层级 --- */ /* 卡片:纯白,用于突显内容 */ --card: oklch(1 0 0); --card-foreground: oklch(0.15 0.02 240); --popover: oklch(1 0 0); --popover-foreground: oklch(0.15 0.02 240); /* --- 核心交互:电光群青 (Electric Ultramarine) --- */ /* H=265, L=0.52 (稳重), C=0.23 (高饱和,极具能量) */ --primary: oklch(0.52 0.23 265); --primary-foreground: oklch(1 0 0); /* 纯白字 */ /* --- Agent 辅助色:数据青 (Data Teal) --- */ /* H=190, 用于区分 Agent 的消息气泡或次要按钮 */ /* 浅色模式下是极淡的青色背景 */ --secondary: oklch(0.96 0.03 190); /* 对应的深青色文字 */ --secondary-foreground: oklch(0.25 0.06 190); /* --- 弱化信息 --- */ --muted: oklch(0.96 0.002 240); --muted-foreground: oklch(0.50 0.02 240); /* --- 强调与强调色 --- */ --accent: oklch(0.96 0.02 240); /* 悬停时的微光 */ --accent-foreground: oklch(0.15 0.02 240); /* --- 状态色 --- */ --destructive: oklch(0.58 0.24 28); /* 警告红 */ --border: oklch(0.92 0.005 240); /* 锐利的边框 */ --input: oklch(0.92 0.005 240); --ring: oklch(0.52 0.23 265); /* 聚焦时显示主色光环 */ /* --- 图表色:蓝/青/紫 科技渐变 --- */ --chart-1: oklch(0.52 0.23 265); /* 主蓝 */ --chart-2: oklch(0.60 0.18 190); /* 青色 */ --chart-3: oklch(0.55 0.20 280); /* 紫色 */ --chart-4: oklch(0.70 0.15 220); /* 浅蓝 */ --chart-5: oklch(0.60 0.05 240); /* 灰色 */ --radius: 0.625rem; /* --- Sidebar (新版 shadcn) --- */ /* 侧边栏比背景稍深一点点,增加层次 */ --sidebar: oklch(0.98 0.002 240); --sidebar-foreground: oklch(0.15 0.02 240); --sidebar-primary: oklch(0.52 0.23 265); --sidebar-primary-foreground: oklch(1 0 0); --sidebar-accent: oklch(0.95 0.01 240); --sidebar-accent-foreground: oklch(0.15 0.02 240); --sidebar-border: oklch(0.92 0.005 240); --sidebar-ring: oklch(0.52 0.23 265); }
首先,这是我根据自己的一个小项目修改过的颜色。虽然它不是官方默认的配置,但背后的逻辑是一致的。
我们可以看到里面几个核心的颜色变量:
background、primary、card、popover 等,这些是常用组件的背景色。而 foreground 则代表在对应背景色上的字体颜色。
这就是 shadcn 设计颜色的逻辑。
但你可能已经注意到了,这里的颜色函数并不是传统的 Hex(16 进制),甚至不是 HSL。
这就是这篇文章想探讨的内容:电脑上的颜色,或者说前端开发中的颜色,到底是怎么回事?
通常,我们会使用最简单的 Hex 16 进制(如 #ffffff)来表示颜色。

但 Hex 有一个问题:它无法直观地体现颜色的三个核心维度。这三个维度分别是:
-
- 色相 (Hue):颜色本身(如红、蓝、绿)。
-
- 饱和度 (Saturation):颜色的“浓度”或强度。
-
- 亮度 (Lightness):颜色的明暗程度,就像光线照在颜色上的强弱。
在 Hex 16 进制中,这三个维度是混合在一起的,你很难通过修改 16 进制数值来精确地微调明度或饱和度。在色彩理论中,颜色本身被称为 色相 (Hue)。
于是有了 HSL 模式:H (Hue) 代表色相,S (Saturation) 代表饱和度,L (Lightness) 代表亮度。
但 HSL 依然有一个缺陷:它的饱和度(S)并不完全符合人眼对颜色的感知。因此,OKLCH 应运而生。OKLCH 模式下,C (Chroma) 取代了 S (Saturation),它能更真实地模拟人眼感知的颜色浓度。
虽然依旧保留了 H,但 S 变成了 C (Chroma,即色度)。
为了方便大家理解,我推荐一个工具网站(https://huetone.zeabur.app/),它可以让你清晰地观察并调整 design token 的 L、C、H 三个变量。

在这个工具中,左侧可以选择各大主流前端框架的颜色模式(Pattern)。你会发现不同品牌的开源组件库,其颜色定义方式各有千秋:有的以 primary、secondary 命名(这是主流做法),有的则直接用颜色名(如 purple、teal)配合梯度(如 Tailwind 的做法)。
当你点击某个颜色时,右侧会展示该颜色的完整色阶(因为颜色通常伴随着浓度和明暗的变化)。例如 primary-500、400、600 等。你可以针对每一个级别,细致地调整它的饱和度、亮度和色相。

当然,这种精细的调节更适合设计师。对于他们来说,可能需要花上几天时间来为某个品牌打磨出一套完美的颜色组合。
但对于我们开发者来说,如果只想快速为一个 Demo 调出一套不错的颜色,有一个“偷懒”的小技巧(Trick):使用 TweakCN (tweakcn.com)。它是一个专门为 shadcn UI 设计的主题配置工具,比官方编辑器更轻量好用。它可以让你快速选定 primary、secondary 等核心色调,并实时预览效果。此外,它还支持配置的导入和导出,非常方便我们将生成的 CSS 变量直接复制到项目中。接着,我们可以结合 shadcn 官网最新的 “Create” 功能来选择字体、图标和圆角,最后再通过这些工具微调一些细节,就能得到一个视觉效果非常成熟的界面了。


如何寻找配色灵感?
最后,还有一个最关键的问题:我们去哪里找那些好看的颜色呢?
对于没有美术背景的开发者,我建议从以下两个渠道入手:
专业配色方案网站
利用现成的调色盘模板,这通常是最稳妥的做法。比如 Coolors (coolors.co) 这种专门收集颜色组合的网站,它提供了海量已经搭配协调、符合视觉心理学的方案,你只需要在里面挑选符合你产品调性的颜色即可。
![[Pasted image 20251221180248.png]]
建立自己的“设计参考库”
审美是需要长期“喂养”的。平时在浏览网页或使用 App 时,看到优秀的 UI 设计一定要养成收藏的习惯,这样在需要用到时就能快速浏览寻找参考。我个人比较推荐经常逛逛 Dribbble (dribbble.com)、Behance (behance.net) 以及专注于移动端设计的 Mobbin (mobbin.com) 等网站。