首页
博客 前端

设计令牌:让深浅两套主题只有一份真相

从散落各处的色值,收敛成一套语义变量;再让 Tailwind 的工具类直接读这套变量,代价和收益都写在这里。

1 周前 1 分钟读完 320 字

双主题最常见的坏味道,是同一个组件里出现 #fff、#FFFFFF 和 bg-white 三种写法。改一次深色模式,就要全局搜索一遍。

分层:基础令牌与语义令牌

  • 基础令牌描述「量」:字号、间距、圆角、阴影、动效时长。
  • 语义令牌描述「意」:--c-canvas、--c-surface、--c-ink、--c-brand。

组件只允许读语义令牌。这样一来,换配色只需要改 themes.css 里的两组值,组件一行都不用动。

:root { --c-surface: #ffffff; --c-ink: #20283a; }
[data-theme='dark'] { --c-surface: #1b2232; --c-ink: #e8edf8; }

让 Tailwind 读变量

Tailwind 4 的 @theme inline 可以把自定义属性映射成工具类,于是 bg-surface 生成的其实是 background-color: var(--c-surface),主题切换自动生效,不需要 dark: 前缀。

好处是组件里只出现 text-ink-soft 这样的语义类;代价是不能再用「颜色名」思考问题,得先想清楚这块区域扮演什么角色。

三个坑

  1. 对比度:深色模式的主文字不能直接反相,#E8EDF8 比纯白更耐看。
  2. 阴影在深色下几乎不可见:用边框承担层次,阴影只做轻微托底。
  3. 动效时长要成对出现:200ms 进、200ms 出,不要一边 150 一边 300。

结果

现在整个站点没有任何硬编码颜色,主题切换只是 data-theme 变了一个值。