行高 (Line Height) — 是两个连续文本行基线之间的距离。与行间距(leading)不同,行高包括字体的完整高度 — 从升部(ascender)的上边界到降部(descender)的下边界加上额外间距。根据 Apple HIG — 排版(2025)的数据,移动应用中正文的最佳行高为字体大小的 1.3–1.5 倍,这可以在不损失界面垂直密度的情况下提供舒适的阅读体验。
要点
行高 (Line Height) — 是排版的基本参数,决定连续行基线之间的距离。在 Web 和移动开发中,行高设定文本的垂直节奏:每行占据特定的高度,该参数在切换到下一行时累加。行高不仅包括字形的实际高度(升部 + 降部),还包括提高可读性的额外空间。
数学上,行高表示为:line-height = font-size × multiplier。如果 font-size = 16 px,multiplier = 1.5,则 line-height = 24 px。此情况下的行间距(leading)为 24 - (ascender + descender) 像素。大多数设计系统和平台都使用倍数,因为它在字体大小变化时自动缩放。
根据 Material Design 字体比例(2025),行高是与字号和字重并列的应用排版系统的三个关键参数之一。为排版层次的所有级别协调的行高值创造了垂直节奏,使界面在视觉上具有整体性。行高偏离最佳值 10% 就已经肉眼可见,并降低界面的感知质量。
| 文本类型 | 字号 | 行高(倍数) | 行高(px) |
|---|---|---|---|
| H1 标题 | 32 pt | 1.15–1.25 | 37–40 pt |
| H2 标题 | 24 pt | 1.2–1.3 | 29–31 pt |
| 正文 | 16 pt | 1.4–1.6 | 22–26 pt |
| 说明文字 | 12 pt | 1.3–1.5 | 16–18 pt |
| 按钮 | 14 pt | 1.0–1.1 | 14–15 pt |
行间距 (Leading)(发音为 "lending")— 是一个历史性的排版术语,表示从基线到基线减去字形高度的行间距离。在金属排字中,行间距是插入行间以增加距离的铅条。行高 — 是一个更现代的概念,包括字体高度和行间距。
在实践中,区别在将设计稿从 Figma 或 Sketch 转移到代码时很重要。设计工具通常显示 行高(或简单地说是行的高度)。在移动平台上,API 可能名称不同:iOS 使用术语 lineSpacing(更接近行间距)以及 minimumLineHeight/maximumLineHeight,Android 使用 LineHeightStyle 带 alignment 和 trim,Flutter 使用 height(无单位倍数)。
// iOS:行高和行间距之间的区别
let paragraphStyle = NSMutableParagraphStyle()
// 1. 直接设置行高
paragraphStyle.minimumLineHeight = 24
paragraphStyle.maximumLineHeight = 24
// 2. 行间距(行之间的额外空间)
paragraphStyle.lineSpacing = 4.0 // 添加到字体的自然行高
关键区别:如果设置 minimumLineHeight,所有行将具有相同的高度,这对于节奏网格很好。如果只设置 lineSpacing,行高将根据字体大小而变化 — 这是一种更灵活但可预测性较差的方法。对于设计系统,建议使用 minimumLineHeight,因为它提供严格可控的结果。
根据 IBM Carbon 设计系统 — 排版指南(2025),行高和行间距之间的差异在使用自定义字体时尤其明显。如果字体具有较大的内置行间距(例如 SF Pro),lineSpacing = 0 可提供可接受的结果。如果字体的行间距较小(某些开源字体),没有额外的 lineSpacing,行将看起来粘在一起。
最佳 行高 取决于几个因素:字体大小、行长、字体和目标受众。对于移动设备上的正文(行长 35–55 个字符),建议范围为字体大小的 1.4–1.6 倍。该值提供了足够的垂直间隔,以便在行之间舒适地移动视线,而不会失去文本的视觉连贯性。
对于标题,行长通常较短(2–6 个词),行高可以更小 — 字体大小的 1.1–1.25 倍。标题不需要大的行间距,因为它们的主要功能是吸引注意力,而不是长时间阅读。此外,大标题尺寸(24–32 pt)配合 1.5 的行高会创建破坏页面垂直节奏的过多间距。
// Flutter:设计系统中的行高
class AppTextStyles {
static const body = TextStyle(
fontSize: 16,
height: 1.5, // line-height 24px
);
static const headline = TextStyle(
fontSize: 28,
height: 1.2, // line-height 33.6px
);
static const caption = TextStyle(
fontSize: 12,
height: 1.4, // line-height 16.8px
);
}
根据 W3C — 排版的可访问性要求(2025),正文行高低于 1.2 被视为可访问性障碍:阅读障碍和视力障碍的用户在阅读密集文本时遇到显著困难。WCAG 2.2 建议主要内容行高至少为 1.5,但在移动界面中,考虑到屏幕宽度有限,该值可以降低到 1.4。
在 iOS 中,行高通过 NSMutableParagraphStyle 或 SwiftUI 的内置修饰符进行管理。在 UIKit 中,有三个关键属性可用:minimumLineHeight 和 maximumLineHeight(设置精确的行高)以及 lineSpacing(行之间的额外间距)。使用 TextKit(NSTextStorage、NSLayoutManager)时,行高在 lineFragmentRect 中被考虑,并影响文本块几何体的计算。
// iOS UIKit:通过 NSMutableParagraphStyle 设置行高
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = 24
paragraphStyle.maximumLineHeight = 24
// 重要:minimum + maximum = 固定行高
let attributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 16),
.paragraphStyle: paragraphStyle
]
let label = UILabel()
label.attributedText = NSAttributedString(
string: "Text with fixed line height",
attributes: attributes
)
在 SwiftUI 中,行高通过 .lineSpacing(value) 修饰符设置,该修饰符在行之间添加额外空间,或通过 .font 使用包含行高的自定义 TextStyle。SwiftUI 还支持动态类型:设置的行高在用户在设置中更改字体大小时会缩放。
// SwiftUI:通过 lineSpacing 设置行高
Text("具有自定义行间距的文本
第二行
第三行")
.font(.body)
.lineSpacing(4) // 行之间的额外空间
// SwiftUI:通过自定义样式设置固定行高
Text("行高 1.2 的标题")
.lineSpacing(0)
.font(Font.system(size: 28, weight: .bold))
.padding(.vertical, 3) // 精确行高的补偿
根据 Apple HIG — 排版实现(2025),通过 minimumLineHeight 使用固定行高时,需要确保该值不小于字体的自然行高。如果 minimumLineHeight 小于 ascender + descender,UIKit 将忽略设置并使用自然高度。这可能在更改字体或大小时导致意外结果。
在 Android 开发中,行高在经典的 View 系统和 Jetpack Compose 中以不同方式管理。在 View 系统中,使用 TextView.setLineSpacing(extra, multiplier) 方法。参数 extra — 以像素为单位的额外空间,multiplier — 自然行高的倍数。最终高度 = 自然行高 × multiplier + extra。
// Android View 系统:行间距
val textView = TextView(context)
textView.text = "Text with custom line spacing"
textView.setLineSpacing(4f, 1.0f) // extra=4px, multiplier=1.0
// 在 XML 中使用
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lineSpacingExtra="4dp"
android:lineSpacingMultiplier="1.4" />
在 Jetpack Compose 中,使用 LineHeightStyle 类管理行高,该类允许设置行间距的对齐(Alignment)和修剪(Trim)。这提供了比简单倍数更精细的控制。例如,可以指定额外的行间距应平均分布在行的上方和下方(align.Center)或完全添加到上方(align.Top)。
// Jetpack Compose:LineHeightStyle 示例
Text(
text = "示例文本
在 Jetpack Compose 中使用自定义 LineHeightStyle",
style = MaterialTheme.typography.bodyLarge.copy(
lineHeight = 24.sp,
lineHeightStyle = LineHeightStyle(
alignment = LineHeightStyle.Alignment.Center,
trim = LineHeightStyle.Trim.Both
)
)
)
// 通过 TextStyle 的简单倍数
Text(
text = "行高倍数",
style = LocalTextStyle.current.copy(
lineHeight = TextUnit(1.5f, TextUnitType.Em)
)
)
根据 Android Developers — Compose 文本样式(2025),LineHeightStyle.Trim.None(默认)保留第一行和最后一行的间距,这可能会干扰 Card 或 Column 中的对齐。建议对固定高度的容器使用 Trim.Both,对下边缘重要的文本块使用 Trim.LastLine。
在 Flutter 中,行高通过 TextStyle 类的 height 属性设置。这是字体大小的无单位倍数:height: 1.5 配合 fontSize: 16 产生 line-height 24.0。height 值隐式乘以 fontSize,因此当大小改变时,行高按比例缩放。Flutter 还提供 StrutStyle — 一种独立于行中实际字形强制固定行高的机制。
// Flutter:通过 TextStyle.height 设置行高
Text(
'行高 1.5 的文本',
style: TextStyle(
fontSize: 16,
height: 1.5, // line-height = 24 px
),
)
// Flutter:StrutStyle 用于固定行高
Text(
'带有 StrutStyle 的文本
固定行高
独立于字形',
style: TextStyle(fontSize: 16),
strutStyle: StrutStyle(
fontSize: 16,
height: 1.5,
forceStrutHeight: true,
),
)
StrutStyle 对于不同大小的列表(例如聊天、新闻推送)特别有用,其中所有行必须具有相同的高度,无论内容如何。没有 StrutStyle,仅包含无降部字母的行将比包含 "p" 和 "y" 字母的行具有更小的实际高度,导致滚动时文本抖动。
根据 Flutter 文档 — 文本布局(2025),带有 forceStrutHeight: true 的 StrutStyle 保证每行的高度等于设定值,而实际字形在此空间内沿基线对齐。这是文本列表的标准方法,其中垂直节奏对视觉感知至关重要。
移动应用在不同屏幕尺寸、像素密度和可访问性设置的设备上运行。行高 必须适应这些变化,保持可读性。基本规则:使用无单位倍数(unitless),而不是 px 或 pt 中的固定值,以便行高随字体大小一起缩放。
使用 Dynamic Type(iOS)或 fontScale(Android)时,字体大小可能相对于基础增加 20–50%。通过倍数设置的行高会自动缩放。如果行高设置为固定值(例如,字体大小 16 pt 时 24 px),当字体增加到 22 pt 时,相对行高将降低到 1.09 — 这已经低于可读性阈值。
// iOS:使用 Dynamic Type 的自适应行高
let font = UIFont.preferredFont(
forTextStyle: .body,
compatibleWith: traitCollection
)
// 从动态字体计算行高作为倍数
let lineHeightMultiplier: CGFloat = 1.5
let lineHeight = font.lineHeight * lineHeightMultiplier
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = lineHeight
paragraphStyle.maximumLineHeight = lineHeight
根据 Material Design — 响应式排版(2025),对于平板电脑和大屏幕(宽度超过 600 dp),建议将正文的行高相对于手机增加 0.1–0.2,因为行长变大。对于可折叠设备,屏幕宽度动态变化,行高应在每次配置更改时重新计算。
常见问题
行高 — 从基线到基线的完整行高,包括字形高度和间距。行间距(leading)— 仅是行之间的额外空间,不包括字形高度。iOS lineSpacing — 这是行间距(额外空间),而 minimumLineHeight — 是完整的行高。在 Android 中,setLineSpacing(extra, multiplier) 结合了两种方法。
对于正文(16–18 pt),最佳 行高 — 字体大小的 1.4–1.6 倍。Material Design 推荐 1.5,Apple HIG 推荐 1.4–1.5。对于长行文本(平板电脑)选择上限(1.6),对于短行(手机)选择下限(1.4)。低于 1.3 的值被视为阅读障碍用户的可访问性障碍。
在 Jetpack Compose 中,使用 TextStyle.lineHeight 配合 TextUnit(可以用 sp 或 em)以及可选的 LineHeightStyle 来管理对齐。示例:Text(text = "文本", style = LocalTextStyle.current.copy(lineHeight = 24.sp, lineHeightStyle = LineHeightStyle(Alignment.Center, Trim.Both)))。对于简单情况,lineHeight = 1.5.em 就足够了。
iOS UILabel 忽略 minimumLineHeight,如果设置的值 小于字体的自然行高(ascender + descender + leading)。此外,如果 UILabel 的 numberOfLines = 1,行高可能不生效 — 该属性仅影响多行文本。要强制执行,请使用带 NSMutableParagraphStyle 的 attributedText,而不是标准的 text 属性。
行高 直接影响可访问性:WCAG 2.2 建议主要内容行高至少为 1.5(AA 级)。阅读障碍、视力低下和认知障碍的用户阅读具有舒适行间距的文本快 20–30%。同时,行高必须随 Dynamic Type 和 fontScale 缩放 — px 中的固定值会破坏可访问性。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。