字体与色彩系统
设计系统只需要两张表:字号阶梯和中性色阶。把这两张表定下来,页面就不会「平」。
首要原则:系统的作用是限制,不是选择。 一个只有 6 个字号、5 级灰、1 个强调色的系统,产出的页面一定好过一个有 20 个自由值的页面。
一、字体
1.1 选字
规则:一到两套。 一套能干的字,胜过两套打架的字。
| 用途 | 选择标准 | 常见可用 |
|---|---|---|
| UI / 正文 | 骨架清晰、字重齐全(300–700)、小字号不糊 | Geist、Satoshi、Plus Jakarta Sans、思源黑体 / 苹方 / 鸿蒙黑 |
| 展示 / 标题 | 有明确个性,大字号下有细节 | Clash Display、Cabinet Grotesk、PP Editorial New、思源宋体、Source Serif |
| 它能用吗 | 只在有授权、或系统预置时 | — |
要避免的:Inter、Roboto、Arial、Open Sans 作为唯一字体。原因不是它们丑,是它们无处不在——它们就是「默认值」本身,而默认值读起来就是没有判断。
另一类要小心的是「模型最爱的展示字体」。 有一小批 display serif 已经被生成工具用烂了(Fraunces、Instrument Serif、Playfair Display 这类)。它们单看很漂亮,但如果你是因为「想显得高级」而选它,那你只是从一个默认值换到了另一个默认值——而且这个默认值更明显,因为大家都在用。
判断标准:能说出为什么是这个字体(气质、历史、骨架特征、和品牌的联系),才用。说不出,就还是默认值。
如果因为项目限制必须用一个无个性的 sans,那就只用一个,把全部精力放在字号对比、字距、留白上。中等个性 × 好的节奏 > 强个性 × 平庸节奏。
1.2 比例字号阶梯
不要用等差(16/18/20/22)。用比例:
比率 1.25(紧凑,信息密集界面) 12 · 14 · 16 · 20 · 25 · 31 · 39 · 49 · 61 比率 1.333(推荐,通用) 12 · 14 · 16 · 21 · 28 · 38 · 50 · 67 · 89 比率 1.5(张扬,营销页 / 编辑型) 12 · 16 · 21 · 28 · 38 · 50 · 75 · 113
挑一个比率,从头用到尾。 阶梯里只允许出现表内的值,不允许临时插一个 18px。
密集界面用 1.25,通用用 1.333,落地页可以 1.4–1.5。页面越营销化,比率越大——因为需要更极端的对比来制造视觉重力。
1.3 流体字号
用 clamp() 让字号随视口连续变化,避免断点跳变:
css:root { --step--1: clamp(0.8125rem, 0.79rem + 0.11vw, 0.875rem); --step-0: clamp(1rem, 0.96rem + 0.19vw, 1.125rem); --step-1: clamp(1.25rem, 1.17rem + 0.38vw, 1.5rem); --step-2: clamp(1.5625rem, 1.41rem + 0.76vw, 2rem); --step-3: clamp(1.9375rem, 1.66rem + 1.39vw, 2.75rem); --step-4: clamp(2.4375rem, 1.92rem + 2.58vw, 3.875rem); --step-5: clamp(3rem, 2.13rem + 4.35vw, 5rem); }
公式:clamp(最小值, 基准rem + 斜率vw, 最大值)。斜率 = (最大px - 最小px) / (最大vw - 最小vw) / 16。
1.4 字距规则
cssh1, .display { letter-spacing: -0.03em; } /* ≥ 48px */ h2 { letter-spacing: -0.02em; } /* 32–47px */ h3 { letter-spacing: -0.01em; } /* 24–31px */ body { letter-spacing: 0; } .eyebrow, .allcaps { letter-spacing: 0.08em; text-transform: uppercase; } /* ≤ 13px */
字号越大,字距越紧。 这是光学补偿:大字号下字间空白在视觉上被放大。不做这一步,大标题会散。
1.5 行高规则
| 内容 | 行高 |
|---|---|
| 展示标题(≥ 48px) | 0.98 – 1.06 |
| 大标题(32–47px) | 1.08 – 1.15 |
| 小标题(20–31px) | 1.2 – 1.35 |
| 正文 | 1.55 – 1.7 |
| 长文正文 | 1.7 – 1.8 |
| UI 标签 / 按钮 | 1.2 – 1.3 |
| 表格行 | 1.4 – 1.5 |
标题行高和正文字高必须反向。 AI 味的典型症状是标题 1.5(松垮)+ 正文 1.3(挤)。
1.6 行长与对齐
- 正文
max-width: 62ch(55–75ch 之间)。 - 居中文本只用于 ≤ 2 行的短内容;超过 2 行一律左对齐。
text-wrap: balance用于标题(≤ 6 行时有效),text-wrap: pretty用于正文。- 移动端正文不要贴边:左右各留 20–24px。
1.7 数字排版
css.num, table td.num, .price { font-variant-numeric: tabular-nums; }
任何会对齐的数字列(价格、指标、表格、计时)都必须用等宽数字,否则纵向读不成线。这是最容易被忽略、也最容易看出廉价的一处。
1.8 中文排版细则(重点)
绝大多数设计系统文档只考虑拉丁字母。中文页面的问题不在「换个中文字体」,在下面这些细节——它们全部是拉丁排版经验的直接移植会造成的事故。
| 项 | 做法 | 不做会怎样 |
|---|---|---|
| 不要移植拉丁的紧行高 | 中文正文行高 1.55–1.7;标题 1.2–1.35。拉丁海报标题常用的 0.95 行高在中文里会变成字挤字 | 中文方块字没有拉丁的下伸部和 x-height 落差,紧行高直接糊成一团 |
| 字重 | 中文「中等粗」用 500,不要用 700 | 中文字形笔画密度高,700 在小字号会糊,看起来像印刷事故 |
| 正文最小字号 | 中文正文 16–18px,不小于 16px | 中文笔画比拉丁密,15px 以下笔画粘连、识别变慢 |
| 中西文空隙 | 中西文之间留约 1/4 全角空隙。CSS 支持时用 text-spacing / text-autospace;不支持时用零宽空格或手工断行 | 直接混排会让「用 API 接入 40+ 模型」读起来像一串噪声 |
| 标点 | 全角标点;引号用「」不用 "";破折号用 ——;省略号用 …… | 半角标点在中文字体下会缩成一个小点,且左右间距错乱 |
| 避头尾 | line-break: strict,避免标点出现在行首 | 顿号、句号行首是中文排版里最刺眼的错误 |
| 可以手工断行 | 标题、按钮、关键短语允许用 <br> 或 text-wrap: balance 指定断点 | 中文没有词间空格,浏览器断行点经常很难看 |
| 数字和单位不断行 | 关键数值和单位用 white-space: nowrap 包住 | 「1,240 万」被拆成两行,数字失去可读性 |
| 数字用等宽 | font-variant-numeric: tabular-nums | 中文语境下表格里的数字对齐问题更明显(中文标签宽度不齐会放大它) |
| 字体栈写全 | 中文回退链要完整,最后落到 sans-serif | 漏了回退会掉进系统默认宋体,与设计意图完全不符 |
| 西文用拉丁字体、中文用中文字体 | 字体栈把拉丁字体放前面,中文字体放后面 | 让中文字体渲染拉丁字母,通常字重和宽度都不对 |
css/* 中文优先的项目:拉丁字体在前,中文字体在后 */ font-family: "Geist", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif; line-height: 1.65; /* 正文 */ font-weight: 500; /* 代替 700 表达中等粗 */ text-wrap: pretty;
中文项目的一条额外规则:数字和单位、型号名(deepseek-v3、gpt-4o)不要交给中文标点规则处理,用 nowrap + 拉丁字体包裹。
1.9 中文排版自检
- 正文行高 ≥ 1.55(而不是拉丁常用的 1.4)
- 正文 ≥ 16px
- 有没有用 700 冒充中文粗体?
- 中西文之间有没有留空隙?
- 有没有标点跑到行首?(
line-break: strict) - 数字和单位会不会被断行?
- 价格、指标、表格里的数字用了
tabular-nums吗?
二、色彩
2.1 一个强调色原则
一页只允许一个颜色承担「强调」职责。
默认状态是中性灰阶,强调色只出现在:主 CTA、当前选中项、关键数字、状态点。出现频率越低,越有力。
如果发现需要第二个强调色(例如成功/错误),它属于语义色,不算强调色——但必须降饱和,且只在有语义时出现。
2.2 中性色阶
建 6 级,全部带一点色相倾向(不要死灰):
css:root { --n-0: oklch(98.5% 0.004 85); /* 页面底 · 暖白 */ --n-1: oklch(96.5% 0.006 85); /* 抬升表面 */ --n-2: oklch(92% 0.008 85); /* 分隔 / 禁用底 */ --n-3: oklch(72% 0.010 85); /* 次要文字 */ --n-4: oklch(45% 0.012 85); /* 正文 */ --n-5: oklch(22% 0.014 85); /* 标题 */ --n-6: oklch(13% 0.016 85); /* 近黑 / 深色表面 */ }
要点:
- 不要用纯
#000或#FFF,用 L* ≈ 13 的近黑和 L* ≈ 98.5 的暖白。 - 色相(85 附近是暖色)按品牌往冷或往暖偏 3–10 度,让灰有温度。
- 对比度:正文对底色 ≥ 4.5:1,大字号 ≥ 3:1,次要文字 ≥ 4.5:1(不要靠「次要」来给低对比找借口)。
2.3 深色表面
至少有一屏用深色表面制造对比。做法:
- 不要用
#000,用--n-6。 - 深色屏上的正文用
--n-2,标题用近白,不要纯白满屏。 - 深色屏上的强调色需要提亮 10–15% 明度,否则在深底上发闷。
2.4 用层级代替边框
三种表达「这里是一个独立区块」的手法,按优先级:
- 背景色阶差(
--n-0上放--n-1的卡片)—— 最干净 - 发丝线(
1px solid color-mix(in oklab, var(--n-4) 12%, transparent))—— 只在需要明确分割时 - 阴影(见下)
不要到处用 1px 灰实线。 满屏边框是廉价感最快的来源之一。
2.5 阴影配方
默认阴影(shadow-md/lg/xl)太重,会把界面压成「2015 年 Material Design」。
css/* 抬升 1 级:卡片 */ --shadow-1: 0 1px 2px rgb(0 0 0 / 0.04), 0 4px 12px -2px rgb(0 0 0 / 0.05); /* 抬升 2 级:悬浮 / 弹层 */ --shadow-2: 0 2px 4px rgb(0 0 0 / 0.04), 0 12px 28px -6px rgb(0 0 0 / 0.07); /* 抬升 3 级:模态 */ --shadow-3: 0 4px 8px rgb(0 0 0 / 0.05), 0 24px 56px -12px rgb(0 0 0 / 0.10);
要点:
- 总透明度 < 0.12,单层 < 0.06。
- 两层叠加:一层贴身(小偏移 + 小模糊)定形,一层远投(大偏移 + 大模糊)定体积。
- 大模糊用负 spread 收口,避免阴影糊出边框。
- 深色主题下阴影不可见,改用提亮表面 + 发丝高光边框表达层级。
2.6 圆角
| 元素 | 圆角 |
|---|---|
| 小控件(tag、checkbox) | 4–6px |
| 按钮、输入框 | 8–10px |
| 卡片、面板 | 12–16px |
| 模态、大容器 | 20–24px |
| 药丸(仅限真胶囊语义) | 9999px |
rounded-full 不要当默认值。 所有东西都是药丸 = 所有东西都没有形状语言。
2.7 色彩自检
- 有几个颜色在承担强调?必须 = 1
- 中性色阶有几级?必须 ≥ 4,且有色相倾向
- 还在用纯黑纯白吗?
- 正文对比度 ≥ 4.5:1?反复检查最浅的那一层
- 阴影总透明度是否 < 0.12?
- 页面是否大量依赖 1px 灰边框分隔?
- 有没有至少一屏是深色表面?


