卷 III · 字· CH 11· 行长尺 深度 11/28

一行到底放多少字

这件事不归审美管,归眼睛的回扫动作管。而且它是全书少数几个「宽屏比窄屏更容易做错」的地方——手机上你想错也错不了,平板上你不管它就一定错。

45–75 字符中文 20–38 字别什么都撑满

规矩和它的来历

排版界的老规矩:拉丁文正文,一行 45 到 75 个字符(含空格),最佳值在 66 附近。

来历不是美学,是回扫(return sweep)——眼睛读完一行,要跳回下一行的行首。这个动作有两个失败模式:

  • 行太长:跳回去的时候容易落到错的行上,也就是「串行」。而且一行读到一半时,你已经忘了这行开头说了什么。
  • 行太短:回扫太频繁,阅读被切成一段一段,节奏很碎。

量出来

「一行几个字符」不是数出来的,是量出来的:用 Roboto 里 26 个小写字母的平均前进宽度(1022.38 / 2048 em),乘字号,再去除容器宽度。

拉动滑杆,注意这几个结果:

场景宽度16px 正文每行判定
手机竖屏360dp(内容区 328)41.1 字符略窄
大屏手机411dp(内容区 379)47.5 字符舒服
小平板600dp(内容区 552)69.1 字符舒服
平板 / 小窗840dp(内容区 792)99.2 字符太宽
桌面1280dp(内容区 1232)154.3 字符远远太宽
两条能直接查的线

手机竖屏(360dp)几乎卡在下限上。这意味着在手机上,你想把正文做得「太宽」是不可能的——所以这一章对纯手机 App 几乎不构成约束。

但只要屏幕超过 600dp,正文满宽就一定错。而这正是大多数 Android App 在平板上难看的头号原因:它们只是把手机布局拉宽了。

中文的数

中文没有空格分词,每个汉字宽度都是一个 em,所以换算简单得多:

每行汉字数 = 容器宽度 / 字号

经验区间是每行 20 到 38 个汉字,最佳 28 到 32。

你现在读的这段正文是 17px,画板内容区约 600px,也就是每行大约 35 个汉字——按 M 键,标注模式会把它量出来。

为什么中文的上限比拉丁文低

拉丁文的单词有长有短、有升部有降部,这些不规则的轮廓给眼睛提供了「路标」,回扫时容易定位。

汉字全是等宽的方块,一行看过去没有任何路标。所以中文既需要更松的行距(上一章那个 1.6–1.8),也需要更短的行长。

怎么限宽

知道了要限宽,剩下的是在哪儿限。有三种做法,优劣分明:

// ✗ 最差:按百分比。屏幕越宽,正文越长,问题原封不动
Text(text, Modifier.fillMaxWidth(0.8f))

// △ 凑合:写死一个最大宽度。能用,但那个数是拍的
Text(text, Modifier.widthIn(max = 600.dp))

// ✓ 最好:从「我想要几个字符」反推宽度,这个数有出处
val maxTextWidth = with(LocalDensity.current) {
    // 66 字符 × 平均字宽(从字体度量来)
    (66 * 0.499f * MaterialTheme.typography.bodyLarge.fontSize.toPx()).toDp()
}
Text(text, Modifier.widthIn(max = maxTextWidth))

// 更省事的写法:宽了就分栏,而不是拉长
when (windowSizeClass.widthSizeClass) {
    WindowWidthSizeClass.Compact  -> SingleColumn()
    WindowWidthSizeClass.Medium   -> SingleColumn(maxWidth = 600.dp)
    WindowWidthSizeClass.Expanded -> TwoPane()      // 列表 + 详情
}

那个 0.499 是 Roboto 小写字母的平均前进宽度(1022.38 / 2048),来自上一章那台探针。这就是「有出处」的样子——三个月后有人问「为什么是 600dp」,答案不是「看着差不多」,是「66 个字符」。

「响应式」真正在解决什么

这一章值得引出一个更大的结论,因为它纠正了一个很普遍的误解。

响应式不是「让东西跟着屏幕变大」

「屏幕变大时,改变布局,而不是拉伸内容」

《Refactoring UI》里有一节叫「Grids are overrated」,说的就是这件事:不要把什么都做成百分比。界面上的量分成两类——

  • 有固有尺寸的:字号、行高、图标、头像、按钮高度、触摸目标。这些由人的眼睛和手指决定,和屏幕多大毫无关系。48dp 的按钮在平板上还是 48dp。
  • 该响应的:容器宽度、栏数、间距档位、以及「显示几栏」这类布局决策。

把第一类做成百分比,就会得到「平板上一切都被放大了 2 倍」的效果——那看起来像一个给老年人用的手机 App。

Material 3 的窗口尺寸类给的就是第二类的决策点:

尺寸类宽度典型设备该做的布局决策
Compact< 600dp手机竖屏单栏,底部导航
Medium600–839手机横屏 / 小平板单栏但限宽,导航改侧边栏
Expanded840–1199平板 / 小窗桌面双栏:列表 + 详情
Large1200–1599桌面双栏 + 常驻侧边栏
Extra large≥ 1600超宽桌面限住总宽,别再摊开了
最后一行值得单独说

屏幕再宽,内容也该有个上限。一个 2560dp 宽的显示器上,把内容摊满等于强迫用户左右转头。

这也是为什么几乎所有内容型网站在大屏上都是「中间一条,两边留白」——那些留白不是浪费,是在保住行长

本章关掉的自由度本章 2 条 · 累计 31 / 78
  • 「正文容器多宽」——从「66 个字符」反推,不是拍一个 600dp。拉丁文 45–75 字符,中文 20–38 字。
  • 「屏幕变宽了怎么办」——改布局(限宽、分栏),不拉伸内容。有固有尺寸的东西(字号、图标、触摸目标)永远不跟着屏幕缩放。