卷 III · 字· CH 12· 层级配方 深度 12/28

一种字体的五种用法

上一章你已经有了一套字号。但层级不止靠字号——你手上其实有五个旋钮,而新手和熟手的区别就是:熟手每次只拧一两个。

五个旋钮降级不是做小做丑视觉层级 ≠ 文档层级

五个旋钮

要让一段文字比另一段「更重要」,你能动的东西一共这么几样:

① 字号最强,也最贵(占地方)
② 字重很强,不占地方
③ 深浅中等,最省,可逆
④ 字距弱,但气质变化大
⑤ 留白间接:把它孤立出来(第 5 章)

关键在于:它们是可以互相替代的,不是叠加的。

把开关一个个打开。你会发现开到第三个之后,标题并没有变得更清楚,只是变得更吵。

规则:一个层级只花一到两个旋钮

层级的作用是让人一眼分出主次,不是让人感受到你调了很多参数

正文和图注的差别,可以只是深浅。
标题和正文的差别,可以只是字号。
按钮上的文字和正文的差别,可以只是字重。

第 4 章那个「花」,本质就是每个层级都动用了全部五个旋钮,于是所有层级都在用最大音量说话。

降级不是做小做丑

第 2 章说过「一屏只能有一个主动作,其余降级」。这里说清楚降级该怎么做。

随手定

把次要按钮做小、做灰、加个细边框。

  • 触摸目标跟着缩水(第 19 章)
  • 灰到看不清,用户以为是禁用
  • 细边框在深色底上会消失
有出处

尺寸不变,只降视觉重量。

  • 高度、字号、内边距全部保持一致
  • 只去掉填充色(Filled → Outlined → Text)
  • 对比度仍然守 4.5:1,绝不用「禁用灰」

Material 的按钮族就是照这条设计的:ButtonOutlinedButtonTextButton 三者高度完全一样,差别只在填充。

「降级」和「禁用」必须长得不一样

这是很常见的一次撞车:次要按钮用了浅灰,禁用按钮也用了浅灰,于是用户分不清「这个不重要」和「这个不能点」。

可查的判据:禁用态的对比度应该低于 4.5:1(它就该看不清),而次要动作必须高于 4.5:1。两者在数值上是分开的区间,不该重叠。

图标比文字重

一个容易被忽略的失衡来源:同样大小的图标,视觉重量远大于文字。

原因在第 3 章讲过——视觉权重 ≈ 面积 × 亮度差。一个 24px 的实心图标是一整块墨,而 24px 的文字大部分面积是空白(笔画只占其中一小部分)。

图标要主动压一档
  • 图标和它旁边的文字不要用同一个颜色——图标用低一档的(比如文字用 onSurface,图标用 onSurfaceVariant)。
  • 装饰性图标(列表项前面那种)压得更狠,它们不该和内容抢注意力。
  • 唯一的例外是图标本身就是主角时:空态的大插图、成功页的对勾。

反过来也成立:如果你有一排图标按钮,其中一个要突出,给它加填充背景比把它调深更有效——因为填充直接增加了面积。

字距

第四个旋钮最少人用,但它是「专业感」的一大来源。规律只有两条:

大字收紧,全大写放开

字号越大,字距要越紧。字形是按正文尺寸设计的,放大之后字母之间的空隙会跟着放大,看起来就散。所以大标题要给一点负字距。

全大写和小字号标签要放开。大写字母全是等高的方块,挤在一起难辨认;小字号同理。

Material 3 的 token 就是这个规律:displayLarge(57sp)是 −0.25sp,而 labelSmall(11sp)是 +0.5sp

用在哪字号字距
首页主标题42px−0.022 em
章首标题33px−0.015 em
小标题21px−0.008 em
正文17px0
全大写标签任意+0.06 em

中文不要加字距。汉字本身就是等宽方块,加了字距会散架。上面这套只对拉丁文和数字生效——所以如果你的标题是中英混排,负字距会让英文部分变紧而中文部分看起来被挤压,需要单独处理。

视觉层级 ≠ 文档层级

最后一条,来自《Refactoring UI》,纠正一个开发者特别容易犯的直觉错误:

h1 不一定是最大的那个

你的语义结构(哪个是 h1、哪个是 h2)和视觉层级是两套独立的东西

典型例子:一个博客文章页,语义上「网站名」可能是 h1、「文章标题」是 h2。但视觉上文章标题必须是最大的——因为用户点进来是看文章的,不是看网站名的。

另一个:设置页里,「分组标题」(账号、通知、隐私)语义上是标题,但视觉上应该比条目文字更小更淡——因为条目才是用户要点的东西,分组标题只是路标。

这条在 Compose 里尤其容易犯,因为 Typography 的名字带着强烈的语义暗示:headlineLarge 听起来就该给标题用。

// ✗ 按语义选 style
Text("设置", style = MaterialTheme.typography.headlineMedium)
Text("通知", style = MaterialTheme.typography.titleMedium)      // 分组标题
Text("允许推送", style = MaterialTheme.typography.bodyLarge)     // 真正要点的东西

// ✓ 按「你想让人先看哪个」选 style
Text("设置", style = MaterialTheme.typography.headlineMedium)
Text(
    "通知",                                     // 分组标题:路标,压轻
    style = MaterialTheme.typography.labelMedium,
    color = MaterialTheme.colorScheme.primary   // 用颜色而不是字号来标识它
)
Text("允许推送", style = MaterialTheme.typography.bodyLarge)     // 保持最重

选 style 的时候,问的不该是「这在文档结构里是第几级」,而是「我想让人第几个看到它」

卷 III 收尾

字这一卷四章,可以压成一张表:

字号七级阶梯,一屏 ≤ 4 级
行高与字号反比、与行长正比;中文 1.6–1.8
行长拉丁 45–75 字符,中文 20–38 字
层级五个旋钮,一次只拧一到两个
对齐关掉 includeFontPadding,加 Trim.Both

到这里为止,你的界面已经关掉了 34 个自由度,而我们还一个颜色都没碰。下一卷开始碰——那是全书唯一一处「凭感觉」会必然出错的地方。

本章关掉的自由度本章 3 条 · 累计 34 / 78
  • 「怎么区分这两级」——五个旋钮里挑一到两个,不是全上。字重最多三档。
  • 「次要按钮做多小多灰」——尺寸一律不变,只去填充色。对比度仍守 4.5:1,禁用态才允许低于它。
  • 「用哪个 typography」——按「想让人第几个看到」选,不按文档层级选。图标比同尺寸文字重,主动压一档颜色。