从shadcn的更新谈谈前端的颜色

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

![](https://pub-6fcfe1e3fe954d73917791d34e36c699.r2.dev/Pasted image 20251221180747.png)

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

![](https://pub-6fcfe1e3fe954d73917791d34e36c699.r2.dev/Pasted image 20251221180735.png)

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

![](https://pub-6fcfe1e3fe954d73917791d34e36c699.r2.dev/Pasted image 20251221180904.png)

左边是 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);
} 

首先,这是我根据自己的一个小项目修改过的颜色。虽然它不是官方默认的配置,但背后的逻辑是一致的。

我们可以看到里面几个核心的颜色变量:

backgroundprimarycardpopover 等,这些是常用组件的背景色。而 foreground 则代表在对应背景色上的字体颜色。

这就是 shadcn 设计颜色的逻辑。

但你可能已经注意到了,这里的颜色函数并不是传统的 Hex(16 进制),甚至不是 HSL。

这就是这篇文章想探讨的内容:电脑上的颜色,或者说前端开发中的颜色,到底是怎么回事?

通常,我们会使用最简单的 Hex 16 进制(如 #ffffff)来表示颜色。

但 Hex 有一个问题:它无法直观地体现颜色的三个核心维度。这三个维度分别是:

    1. 色相 (Hue):颜色本身(如红、蓝、绿)。
    1. 饱和度 (Saturation):颜色的“浓度”或强度。
    1. 亮度 (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 三个变量。

![](https://pub-6fcfe1e3fe954d73917791d34e36c699.r2.dev/Pasted image 20251221181632.png)

在这个工具中,左侧可以选择各大主流前端框架的颜色模式(Pattern)。你会发现不同品牌的开源组件库,其颜色定义方式各有千秋:有的以 primarysecondary 命名(这是主流做法),有的则直接用颜色名(如 purpleteal)配合梯度(如 Tailwind 的做法)。

当你点击某个颜色时,右侧会展示该颜色的完整色阶(因为颜色通常伴随着浓度和明暗的变化)。例如 primary-500400600 等。你可以针对每一个级别,细致地调整它的饱和度、亮度和色相。

![](https://pub-6fcfe1e3fe954d73917791d34e36c699.r2.dev/Pasted image 20251221181605.png)

当然,这种精细的调节更适合设计师。对于他们来说,可能需要花上几天时间来为某个品牌打磨出一套完美的颜色组合。

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

![](https://pub-6fcfe1e3fe954d73917791d34e36c699.r2.dev/Pasted image 20251221174903.png)

![](https://pub-6fcfe1e3fe954d73917791d34e36c699.r2.dev/Pasted image 20251221174912.png)

如何寻找配色灵感?

最后,还有一个最关键的问题:我们去哪里找那些好看的颜色呢?

对于没有美术背景的开发者,我建议从以下两个渠道入手:

专业配色方案网站

利用现成的调色盘模板,这通常是最稳妥的做法。比如 Coolors (coolors.co) 这种专门收集颜色组合的网站,它提供了海量已经搭配协调、符合视觉心理学的方案,你只需要在里面挑选符合你产品调性的颜色即可。

![[Pasted image 20251221180248.png]]

建立自己的“设计参考库”

审美是需要长期“喂养”的。平时在浏览网页或使用 App 时,看到优秀的 UI 设计一定要养成收藏的习惯,这样在需要用到时就能快速浏览寻找参考。我个人比较推荐经常逛逛 Dribbble (dribbble.com)Behance (behance.net) 以及专注于移动端设计的 Mobbin (mobbin.com) 等网站。