把同一份稿子排两遍。11pt 的 article,行长 180pt,lipsum 的一百个段落。不用 microtype 时得到 1731 行,并出现 117 个 overfull box。在导言区加上一行 \usepackage{microtype},结果是 1702 行、6 个 overfull。所谓微观排版,不过是让标点探出页边一根头发丝的距离,把字形宽度伸缩不到百分之一——如此而已。本页结合实测数字,看看 LaTeX 的 microtype 究竟做了什么:protrusion(突出)、font expansion(伸缩)与 tracking。
microtype 到底在做什么
microtype 自己并不排版。它是 对 pdfTeX 引入、后来部分扩展到 LuaTeX 和 XeTeX 的微观排版功能的统一 LaTeX 接口,作者是 R. Schlicht。核心是两件事——字符 protrusion(也叫 margin kerning)和 font expansion——其后是 tracking(字间距)、连字的禁用,以及词间距与额外 kerning 的调整。只要能安全断定在当前引擎上可用,protrusion 和 expansion 就会 默认启用。
这两项功能的来历有据可查。Hàn Thế Thành 于 2000 年向布尔诺的马萨里克大学提交的博士论文《Micro-typographic extensions to the TeX typesetting system》把它们实现在 pdfTeX 中;该论文以 TUGboat 第 21 卷第 4 期第 317–434 页发表。同一篇论文解释道,margin kerning 是为了视觉上的对齐而必需的,因为机械对齐的边缘在眼中反而显得参差;并把 font expansion 定义为:在松散的行里换用更宽的字体变体,在紧凑的行里换用更窄的,从而减少词间距的伸缩量。换句话说,microtype 实现的是一套从 人眼如何误读一条直边 这一观察出发的机制。
顺带界定一下范围:这些都是针对 西文(拉丁字母) 的精修。日文有另一套排版模型——行首行末的禁则、日文与西文之间的间距——由 luatexja 等工具负责,载入 microtype 并不会改变其中任何一项。至于连字和 kerning 这类更基础的西文自动处理,留给姊妹页面。
microtype 的效果有多大 — 实测
行长越窄,效果越明显。在 TeX Live 2024 上,用 11pt 的 article 加 \usepackage[T1]{fontenc},行长 180pt(约相当于双栏版式的一栏),排入 lipsum 的一百个段落,统计行数和 Overfull \hbox 的条数。结果见下表:加上 microtype 后总行数从 1731 降到 1702(−1.7 %),溢出从 117 降到 6。把同一测量改到 345pt(接近 a4paper 的 article 正文宽度),差距收窄为 921 → 909 行(−1.3 %)。效果确实存在,但谈不上“大幅缩短”。
| 设置 | 总行数(180pt 行长,100 段) | Overfull hbox 条数 |
|---|---|---|
(package not loaded) | 1731 | 117 |
expansion=false | 1718(仅 protrusion) | 102 |
protrusion=false | 1711(仅 expansion) | 9 |
\usepackage{microtype} | 1702(两者,默认) | 6 |
这份拆解表明,两项功能干的是不同的活。削减行数最多的是 expansion(1731 → 1711),不过 protrusion 也贡献了十三行。但 消灭 overfull box 几乎完全是 expansion 的功劳:117 降到 9,而只用 protrusion 只能降到 102。如果有一行探出页边,管用的是 expansion;如果只是觉得右边缘参差,管用的是 protrusion。要决定关掉哪一个时,这条经验法则就够用了。顺带一提,载入 microtype 会把 \pdfprotrudechars 和 \pdfadjustspacing 都设为 2(不载入时两者都是 0),所以用 \the 看这两个值就能确认到底有没有生效。
字符 protrusion:抵消视觉错觉
Protrusion(margin kerning)让行首和行末的字符稍稍越出页边,目的正是抵消一种错觉。把句号、逗号、连字符,或 o、A、v 这类具有 圆形或倾斜轮廓 的字母贴齐文本边缘,字形两侧的留白会让边缘看起来 向内凹。让它们略微突出,边缘在 视觉上 就笔直了。每个字符突出的量并不相同:标点很多,圆形字母少一些,H 这种直边字母则为零——microtype 为每种字体都备有记录这些数值的配置文件。
要整体加大或减小突出量,用 factor 选项(factor=1100 即默认值的 1.1 倍)。此外,在 TeX 看来不算“页边”的地方——itemize 的条目、tabular 的单元格边缘——protrusion 是不起作用的。为此 microtype 提供了 \leftprotrusion 和 \rightprotrusion,让该处的首字或末字像位于普通外边距那样突出。对于左列以括号或引号开头的表格,只要加上它们,观感就会不同。
Font expansion:让字宽替词间距分担工作
Font expansion 会把每行的字形在水平方向上稍作拉伸或压缩——通常是百分之零点几到百分之几——以使行宽合适。在两端对齐中,行宽本来只靠 词间距(interword glue) 的伸缩来达成。把这份工作的一部分交给字宽承担,词间距的波动就更小,行与行之间的空白差异减少,整段的浓淡(排版上说的“颜色”)也更均匀。上面的实测中把 overfull box 从 117 个降到 9 个的,正是这项功能。伸缩上限由 stretch / shrink 设定,步长由 step 设定,不过保持默认通常就没问题。
这里有一条无法回避的限制。expansion 只在 pdfTeX 和 LuaTeX 上可用,XeTeX 上不可用。 在 XeLaTeX 下不带任何选项地载入 microtype 并不会报错——宏包只启用能安全运行的功能,因此 protrusion 和 tracking 照常工作,只有 expansion 被悄悄关掉。但若明确写成 \usepackage[expansion=true]{microtype},编译就会停在下面这条错误上:
$ xelatex xe.tex
! Package microtype Error: Font expansion does not work with xetex.
See the microtype package documentation for explanation.
% The reason is one missing primitive. Asking each engine directly:
% pdftex : has \efcode, has \lpcode
% xetex : NO \efcode, has \lpcode
% luatex : has \efcode, has \lpcode
% XeTeX can shift glyphs into the margin, but it cannot scale their widths.原因可以归结为少了一个引擎原语。用于突出的 \lpcode / \rpcode(左右突出量)三个引擎都有,但 expansion 所需的 \efcode 在 XeTeX 中并不存在(pdfTeX 和 LuaTeX 都有)。也就是说,XeTeX 能把字形挪进页边,却没有办法缩放字形的宽度。若你在 XeTeX 上而又想要包含 expansion 的完整效果,转向 LuaTeX 才是合乎逻辑的选择。
Tracking(\textls):不破坏断词的字间距
Tracking(字间距)/letterspacing 是把字母间距均匀拉开的调整。microtype 的做法之所以出色,在于它并不是在字与字之间塞入空白,而是 生成并使用一份字形更宽的字体副本。因此单词仍然是一个整体,断词不会被破坏。而在单词中间手工撒 \kern 的经典做法,会让这个词从此再也无法在行末断开。临时的字间距用 \textls{...};要对其后所有文字生效则用 \lsstyle,它一直有效到当前分组结束。像标题这种不希望在前后添加额外 kerning 的场合,带星号的 \textls*{...} 很方便。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{microtype}
% Space out small caps by 40/1000 em wherever they appear
\SetTracking{encoding = *, shape = sc}{40}
\begin{document}
\textsc{Small Caps}, and an ad-hoc \textls[200]{wide run of letters}.
% \lsstyle stays on until the end of the group
{\lsstyle everything here is letterspaced}
% The starred form adds no kerning before or after - good for headings
\section*{\textls*{Chapter Title}}
\end{document}数量以千分之一 em 为单位;按 microtype 手册,默认是 100/1000 em = 0.1 em。可以在可选参数里给出一次性的值,例如 \textls[200]{...};也可以在导言区对整组字体声明,如 \SetTracking{encoding=*, shape=sc}{40}(此例把小型大写拉开 40/1000)。这里要提醒一句:手册本身写道,给小写文本加字间距“为人所深恶痛绝”,并告诫说除非你清楚自己在做什么,否则只应对大写字母或小型大写使用字间距。Tracking 可用于 pdfTeX 和 LuaTeX——microtype 的 README 连版本条件都写明了。若在 plain TeX 中也需要字间距,另有只提供这一部分的 letterspace 宏包。
切断连字、调整词间 — \DisableLigatures 与 kerning / spacing
需要禁用连字的场合不多,但真遇上了就很要紧——比如展示代码的句子里,-- 绝不能被合成成 en dash。\DisableLigatures 针对指定的字体集合关闭连字:\DisableLigatures{encoding = T1, family = tt*} 只涵盖 T1 下的等宽字族。但要注意,禁用一个字体的全部连字,也会同时关掉它的 kerning(手册明确写着这一点)。把连字的起始字符列在可选参数中,就只停用指定的连字,例如 \DisableLigatures[?,!]{encoding = T1}。此命令 只能在导言区使用,而且只能用一次。
kerning 与 spacing 选项分别启用 额外的 kerning 和 词间距微调,二者都 仅限 pdfTeX(在 LuaTeX 和 XeTeX 上无效)。它们默认都是关闭的,只在需要时才写出来。载入之后要改设置,用 \microtypesetup{...}——例如只想在生成目录期间关掉 protrusion,就用 \microtypesetup{protrusion=false} 和 \microtypesetup{protrusion=true} 把它夹住。要让文档的某一部分使用另一套设置,可用 \microtypecontext{...}(或 microtypecontext 环境)切换上下文。传入 draft 可一次性关闭微观排版,而 final 反过来,即使文档类处于 draft 模式也强制启用——做前后对比实验时这两者很好用。
可用功能取决于引擎
要点有两条——expansion 在 XeTeX 上不可用,词间距和额外 kerning 仅限 pdfTeX。因此功能最全的是 pdfTeX(protrusion+expansion+tracking+kerning+spacing),其次是 LuaTeX(protrusion+expansion+tracking),XeTeX 则只有 protrusion 和 tracking。microtype 会自动只启用在当前引擎上能安全运行的功能,所以不带参数载入永远不会报错——也正因如此,哪些功能没生效需要你自己心里有数。
| 功能 | pdfTeX / LuaTeX / XeTeX | 备注 |
|---|---|---|
protrusion | 有 / 有 / 有 | 三者都有 \lpcode 和 \rpcode;默认启用 |
expansion | 有 / 有 / 无 | XeTeX 没有 \efcode;显式要求会触发 Package microtype Error |
tracking | 有 / 有 / 有 | \textls 与 \lsstyle;默认关闭,用 tracking 开启 |
kerning | 有 / 无 / 无 | 仅 pdfTeX;默认关闭 |
spacing | 有 / 无 / 无 | 仅 pdfTeX;词间距的微调 |
在导言区实际怎么写
最基本的情形是 只写 \usepackage{microtype} 一行。这会默认开启 protrusion 和 expansion(在引擎支持的前提下),多数文档凭此就已经明显变好。microtype 稳定且几乎没有副作用,加上它几乎不会带来麻烦。在 pdfTeX 系列上,惯例是与 \usepackage[T1]{fontenc} 搭配,这也是因为 protrusion 与 expansion 的配置文件是按编码组织的。下面的例子稍进一步:显式启用 protrusion 和 expansion,轻微拉开小型大写的字间距,并只对展示代码用的等宽字族关闭连字。
\documentclass{article}
\usepackage[T1]{fontenc}
% protrusion and expansion explicitly on;
% "final" forces them on even when the class is in draft mode
\usepackage[activate={true,nocompatibility},final]{microtype}
% letterspace small caps a little (40/1000 em)
\SetTracking{encoding = *, shape = sc}{40}
% no ligatures in the typewriter family, so "--" stays two hyphens
\DisableLigatures{encoding = T1, family = tt*}
\begin{document}
% turn protrusion off just while the table of contents is built
\microtypesetup{protrusion=false}
\tableofcontents
\microtypesetup{protrusion=true}
\end{document}最后校准一下期待。这类调整很含蓄,只看一页也许根本看不出来——实测中总行数也不过缩短了 1.7 个百分点,而且还是在窄行长下。日常写作里更管用的是 overfull box 从 117 个降到了 6 个:每少一次溢出,就少一次为了塞进去而改写句子的功夫。microtype 的价值与其说在于“变短”,不如说在于 减少你动手修补的次数。