连字 是将两个或多个字符图形化连接成一个排版符号,以改善文本的可读性和美观性。经典示例包括 fi、fl、ff、ffi 等组合 — 其中字母 f 的突出部分与相邻字符融合,防止视觉冲突。在现代移动和Web开发中,连字通过 OpenType 功能在字体级别进行管理,并在 iOS、Android 和浏览器中得到支持。根据 MDN Web Docs,CSS 属性 font-variant-ligatures 允许开发者启用和禁用不同类型的连字:标准连字、 discretionary(装饰性)连字和上下文连字。
要点
连字 是一种排版技术,其中两个或多个字符被替换为一个专门设计的符号。连字的主要目的是消除相邻字符之间的视觉冲突并改善文本感知。例如,在 fi 组合中,字母 f 的上部突出与字母 i 的点相撞 — 连字将它们合并为一个优雅的符号。
连字分为必需(标准)和可选(装饰性)两种。标准连字 是大多数字体中出现的组合:fi、fl、ff、ffi、ffl。它们被认为是高质量排版所必需的,默认在字体中启用。根据 OpenType 规范,标准连字使用 'liga' 标签编码,并且应在每个专业字体中启用。
视觉效果:没有连字时,fi 组合看起来像两个带有不期望接触的独立字符。使用连字后 — 像一个和谐的符号。这种差异在大尺寸(标题、标志)和具有大量重复组合的文本(例如,在德语中的 häufigen Buchstabenkombinationen)中尤为明显。
OpenType 字体支持多种类型的连字,每种都有其自己的标签和用途。标准(标签 'liga')— 默认在字体中启用的必需连字。它们改善可读性,不应无故禁用。包含 fi、fl、ff、ffi、ffl 等组合以及其他特定于字体的组合。
Discretionary 连字(标签 'dlig')— 装饰性连字,根据设计师的判断可选择性启用。它们不是可读性必需的,用于文本样式化:ct、st、sp、Th、Qu 等。Discretionary 连字通常出现在具有历史或书法特征的字体中 — 例如在 Garamond 或 Adobe Caslon 中。警告:过多的 discretionary 连字会降低可读性,特别是对于有阅读障碍的用户。
上下文连字(标签 'clig')— 取决于字符环境的连字。它们仅在特定条件下应用:如果字符位于单词的开头或结尾,在特定标点符号之后等。上下文连字是高级 OpenType 功能,并非所有字体都支持。历史连字(标签 'hlig')— 模仿旧式印刷书籍样式的过时连字(long s、&)。很少使用,仅用于历史或样式化文本。
| 连字类型 | OpenType 标签 | 示例 | 默认 |
|---|---|---|---|
| 标准 | liga | fi、fl、ff、ffi | 启用 |
| Discretionary | dlig | ct、st、sp、Th | 禁用 |
| 上下文 | clig | 取决于位置 | 启用 |
| 历史 | hlig | long s、ct(历史) | 禁用 |
罕见类型:还有用于数学排版的连字(用于数学符号的标签 'dlig')和首字母连字(drop caps)— 但它们不用于界面排版,仅由专业字体支持。
连字早在数字排版之前就已出现 — 早在 15 世纪的金属排字时代。印刷商约翰内斯·谷登堡在其 42 行圣经的行中使用连字以节省空间。每个字母都是一个物理金属块,将两个字符合并为一个字母节省了铅料并简化了排版。标准连字 fi、fl、ffi、ffl 是那个时代的遗产。
在照相排字(20 世纪)中,连字失去了其实际功能,但作为高质量排版的美学元素保留了下来。字体设计师继续将连字纳入其字体中,因为它们已成为专业性和注重细节的标志。在数字字体时代(PostScript、TrueType),连字作为独立的字形通过程序替换实现。
OpenType(1996 年) 是一场革命:它引入了 GSUB(字形替换表)机制,可在无需用户干预的情况下自动将字符序列替换为连字。GSUB 支持上下文替换、条件和后备变体。这使得字体可以拥有数百个通过标签启用/禁用的连字。现代字体 — SF Pro、Roboto、Inter — 在所有平台上支持 OpenType 连字:iOS、Android、macOS、Windows、Web。
在 iOS 上,可以通过 UIFontDescriptor 使用 featureSettings 属性来管理连字。此属性接受一个字典数组,每个字典描述一个 OpenType 功能。通过描述符管理连字是控制单个连字类型而不影响字体其他 OpenType 功能的唯一方法。
let descriptor = UIFontDescriptor.preferredFontDescriptor(
withTextStyle: .body
)
// 启用 discretionary 连字
let ligatureDescriptor = descriptor.addingAttributes([
.featureSettings: [
[
UIFontDescriptor.FeatureIdentifier: kLigaturesType,
UIFontDescriptor.TypeIdentifier: kCommonLigaturesOnSelector
]
]
])
let font = UIFont(
descriptor: ligatureDescriptor,
size: 17
)
NSAttributedString 也支持 ligature: NSNumber 属性。值为 0 — 禁用所有连字,1 — 启用标准连字(默认),2 — 启用所有连字(包括 discretionary)。然而,NSAttributedString 中的 ligature 属性不提供对连字类型的精细控制 — 仅为全局启用/禁用。对于选择性管理,使用带有 featureSettings 的 UIFontDescriptor。
SwiftUI 不提供直接的连字修饰符。要在 SwiftUI 中管理连字,请通过 UIFontDescriptor 创建具有所需设置的 UIFont,并通过 Font(descriptor:size:) 使用它。或者 — 在 AppKit/UIKit 视图中对 NSMutableAttributedString 使用带有 .ligature 属性的 AttributedString(iOS 15+)。
// 通过 AttributedString 使用自定义连字的 SwiftUI
var attributedText: AttributedString {
var text = AttributedString(
"Effective typography with ligatures"
)
// 为整个文本启用所有连字
text.ligature = .all
return text
}
var body: some View {
Text(attributedText)
}
在 Web 上,连字通过 CSS 属性 font-variant-ligatures 管理,它接受关键字:common-ligatures(标准启用)、no-common-ligatures(标准禁用)、discretionary-ligatures、no-discretionary-ligatures、contextual、no-contextual。该属性自 2015 年起得到所有现代浏览器的支持。默认情况下,浏览器启用标准和上下文连字。
/* Disable all ligatures for monospace */
code, pre {
font-variant-ligatures: none;
}
/* Enable discretionary ligatures for headings */
.title-fancy {
font-variant-ligatures:
common-ligatures
discretionary-ligatures
contextual;
}
Android 没有用于管理连字的直接 API。在 Android 中,连字在字体和 Minikin 渲染引擎(Android 10+)级别进行管理。如果字体包含 OpenType GSUB 表,连字会自动应用。要在 Android 中禁用连字,使用通过 Typeface.Builder 创建的自定义 Typeface,或进行文本预处理(在显示前替换字符)。限制:在低于 10 的 Android 版本上,连字可能在某些 TTF 字体上无法正常工作。
底层控制:在所有平台上,可以使用带有 font-feature-settings 参数的 CSS @font-face 来管理 OpenType 功能。此方法提供对任何 OpenType 标签的访问,包括连字。示例:font-feature-settings: 'liga' 1, 'dlig' 1。然而,font-feature-settings 是底层语法,MDN 建议使用 font-variant-ligatures 作为更高层的替代方案。
一类特殊的连字 — 编程连字,它将运算符和代码符号组合成更易读的符号。编程字体如 Fira Code、JetBrains Mono、Cascadia Code 包含常见运算符的 discretionary 连字:!=(变为 ≠)、>=(变为 ≥)、->(变为箭头)、=>(变为粗箭头)、===(变为三重等号)。
编程连字在开发者社区中是一个有争议的话题。支持者认为连字加快了代码阅读速度,因为运算符被视为统一的概念。研究(Kera 等人,PLATEAU 2020)表明连字不影响代码阅读速度,但主观上受到 67% 开发者的喜爱。反对连字的人指出它们会扭曲代码:!= 符号在编辑器中显示为 ≠,但在文本文件中存储为两个字符,这在协作时可能会造成混淆。
技术实现:编程连字是 discretionary OpenType 连字(标签 'dlig')。它们默认禁用,在代码编辑器中通过字体设置启用。使用此类字体的开发者必须配置编辑器以启用 discretionary 连字。在终端(iTerm2、Windows Terminal)中,连字也通过字体设置得到支持。兼容性:并非所有编辑器和终端都支持 OpenType 连字。在选择字体之前,请检查与您的工具的兼容性。
// 示例:JetBrains Mono 中的运算符连字
val isEqual = a != b // != 渲染为 ≠
val arrow = x -> x + 1 // -> 渲染为 →
val range = 1 .. 10 // .. 渲染为范围
流行的编程连字字体:Fira Code(第一个具有连字的流行字体,2015 年)、JetBrains Mono(针对代码阅读优化,2020 年)、Cascadia Code(来自微软,2019 年)、Iosevka(具有模块化连字系统的可配置字体)。每种字体都有自己的连字集 — 从 50 到 150+ 个替换。建议:从 Fira Code 或 JetBrains Mono 开始 — 它们在编辑器和 IDE 中具有最佳支持。
常见问题
在 NSAttributedString 中设置 ligature = 0 属性,或使用带有 kCommonLigaturesOffSelector 的 UIFontDescriptor。在 SwiftUI 中 — 使用 .ligature = .disabled 创建 AttributedString。
连字 用一个新的符号替换两个字符,改变其形状。字距调整 调整字符之间的间距,不改变其形状。连字是图形连接,字距调整是空间校正。
是的,从 Android 10(API 29)开始。Minikin 渲染完全支持 OpenType GSUB 表。在较早版本上,支持取决于设备制造商和字体引擎版本。
对于主要文本,标准连字(fi、fl、ff)足够了 — 它们改善可读性且对用户不可见。仅在标题或装饰性文本中使用 discretionary 连字,因为它们会降低长文本的可读性。
编辑器必须支持 OpenType 标签 'dlig' 并能显示 discretionary 连字。VS Code、IntelliJ IDEA、Sublime Text 支持。旧终端和编辑器(nano、无 GUI 的 vim)— 不支持。检查编辑器设置:启用 font-ligatures。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。