行距 (setspace)

“请以双倍行距提交。”期刊这样写的时候,它引用的其实是打字机的尺寸。一台排 12 磅活字的打字机每行送纸 12 磅,把旋钮拨到 2 就送 24 磅——正好够编辑在行间写批注。在 LaTeX 中放宽行距要用的 setspace 宏包,至今仍忠实再现这套尺寸。所以 \doublespacing 并不是把什么东西翻倍,它是把行距设成 恰好为字号的两倍。本页沿着这条线索走完全程:名为 \baselineskip 的长度、\linespread 看似无效的原因,以及 setspace 实际输出的磅值实测结果。

行距的本体是一个叫 \baselineskip 的长度

LaTeX 所说的行距,是从一行的 基线(字母所坐落的那条看不见的线)到下一行基线的距离,保存在名为 \baselineskip 的长度里。要点在于它量的是“一行的推进量”,而不是字与字之间的空隙,所以把字号调大,行距也会自动跟着变大。实测 10pt 的 article\baselineskip 恰好是 12.0pt,正文宽度 \textwidth345.0pt。“行距是字号的 1.2 倍”这条广为流传的经验法则,只有在 10pt 时才严丝合缝。

类选项实际字号baselineskip比值
10pt10pt12.0pt1.200
11pt10.95pt(不是 11pt)13.6pt1.242
12pt12pt14.5pt1.208

表格第二行藏着一个值得记住的事实:11pt 选项实际选中的并不是 11pt 的字,而是 10.95pt。 让 LaTeX 显示 \f@size,它会回答 10.95。这是 Computer Modern 的设计尺寸所致,只有行距被取整成了整齐的 13.6pt。本页后面 setspace 那些看起来零碎的倍率,部分正是为了吸收这 0.05pt 的差额。

\linespread 不起作用:为什么导言区有效、正文里无效

\linespread{1.5} 写在哪里,哪里就什么也不会发生。在下一次重新选择字体之前,\baselineskip 一磅也不会动。 实测结果是:默认 12.0pt,写下 \linespread{1.5} 之后仍是 12.0pt,一旦调用 \selectfont 就变成 18.0pt。看一眼机制就明白了:\linespread{x} 的内容就是 \renewcommand{\baselinestretch}{x},它只是 改写了一张写着“该用哪个倍率”的便条。把这张便条换算成真实长度是 \selectfont 的工作:它把当前生效的倍率与 \baselinestretch 对照,只有两者不一致时才重新计算行距。

症状的分布也就随之解释清楚了。写在导言区的 \linespread 之所以有效,是因为 \begin{document} 会执行 \normalsize,正好在那里重新选择字体。写在正文中就得自己调用 \selectfont;而像 \Large 这样的字号变化,甚至 \bfseries 这样的字重变化,也能起到同样作用——它们内部都会经过 \selectfont。实测中,\linespread{2} 后面只加一个 \large 就得到了 28.0pt。不过局部改动时,别忘了 把收束段落的 \par 放在分组内部。一旦 \par 落到组外,那一段就会以旧的行距排版——这个陷阱由“改变字号的命令”那一页详细讲解。

latex
% In the preamble: applies to the whole document.
\linespread{1.3}          % measured: baselineskip 12.0pt -> 15.6pt

% In the body: nothing happens until the font is re-selected.
\linespread{1.6}          % baselineskip is STILL 12.0pt here
\selectfont               % now it becomes 19.2pt

% One paragraph only. Note the \par INSIDE the braces.
{\linespread{1.6}\selectfont
  This paragraph is set with wider leading.\par}

setspace 的用法:三个声明与 spacing 环境

加载 \usepackage{setspace},在导言区写一行 \onehalfspacing\doublespacing——实务上到此为止。推荐这个宏包有三个理由。其一,像 \setstretch{1.6} 这样的任意倍率 当场生效,因为它内部会重新发出当前的字号命令,不会出现忘写 \selectfont 的事故。其二,\onehalfspacing\doublespacing 背后的倍率是 按正文字号分别调校 的。其三,它不会把脚注和题注一起撑开——下下节会给出实测。

命令或环境作用
\singlespacing恢复默认行距的声明;对其后的内容生效
\onehalfspacing把行距设为字号 1.5 倍的声明
\doublespacing把行距设为字号 2 倍的声明;投稿须知里的“双倍行距”就是它
\setstretch\setstretch{1.6} 指定任意倍率;乘在 \baselineskip
spacing环境:\begin{spacing}{2.5}\end{spacing} 只在该区间改变倍率,结束后自动恢复
singlespace环境:在双倍行距的正文中,让这一段回到默认行距
onehalfspace环境:\onehalfspacing 的局部版本(doublespace 同理)。仅用于 加宽 行距
\SetSinglespace重新定义“单倍”本身的取值(默认 1);用于按标称尺寸偏大的字体的微调
document.tex
\documentclass[12pt]{article}
\usepackage{setspace}
\doublespacing            % whole document: leading 24.0pt at 12pt
% \onehalfspacing        % or 18.0pt
% \setstretch{1.6}       % or any factor you like
\begin{document}
The body is set double spaced.

\begin{spacing}{1}       % one region back to the normal leading
  A long quotation, set tight.
\end{spacing}

Back to double spacing here.
\end{document}

“双倍行距”到底是多少磅:\doublespacing 的实测值

答案是 恰好为字号的两倍:10pt 对应 20pt,11pt 对应 22pt,12pt 对应 24pt。\doublespacing 并不是把 \baselineskip 翻倍,而是从这个目标值反推出倍率。因此各类选项的倍率各不相同,并且落在 1.667、1.618、1.655 这样零碎的数字上。把实测值并排一看,意图就一目了然。

类选项默认行距onehalfspacingdoublespacing
10pt12.0pt1.25 → 15.00pt1.667 → 20.00pt
11pt13.6pt1.213 → 16.50pt1.618 → 22.00pt
12pt14.5pt1.241 → 17.99pt1.655 → 24.00pt

这不是猜测。在 setspace.sty 的源码中,每个定义正上方的注释分别写着 “one and a half spacing is 1.5 x pt size” 和 “double spacing is 2 x pt size”,实测值也正好落在那里。由此得出一个实用结论:\setstretch{2} 不等于 \doublespacing \setstretch{2}\baselineskip 翻倍,在 10pt 文档中得到 24.0pt,比 \doublespacing 的 20.0pt 宽了两成。当规定只写着“双倍行距”时,老老实实用 \doublespacing

顺带用一段说说 setspace 自己的来历。据文件开头的署名,原作者是 Erica M. S. Harris,1992 至 1994 年间由 GDG 改造,Geoffrey Tobin 于 1996 年 2 月 6 日把它改写成 LaTeX2e 宏包,此后 Robin Fairbairns 长期维护,如今版权行已署上 LaTeX Team(TeX Live 2024 收录的是 2022 年 12 月的 v6.7b)。一个只改一个数字的宏包,堆叠了三十年的名字。

脚注和题注不会被撑开:setspace 替你守住的地方

即使正文是双倍行距,脚注和浮动体内部仍保持默认行距。在 12pt 的 article 中施加 \doublespacing 后实测:正文 23.99pt,脚注内 12.0ptfiguretable14.5pt。这是因为 setspace 修补了 \@footnotetext\@mpfootnotetext\@xfloat,在它们内部把倍率恢复为单倍。直接使用 \linespread 没有这份体贴,会把脚注和题注一起拉长——在投稿稿件里,这本身就是体例违规。

另一方面,引用用的 quote 环境 不会 自动收紧。在双倍行距的 12pt 文档中测量 quote 内部,仍然是与正文相同的 23.99pt。这是作者本来的打算——源码里注明,单倍行距的引用要用 quote 包住 singlespace 来做。所以请像下面这样自己嵌套。顺带一提,setspace 也会对陈列公式前后的空白施加倍率(用 \setdisplayskipstretch 调整,用 nodisplayskipstretch 选项关闭)。

latex
% quote is NOT single-spaced by setspace; nest it yourself.
\begin{quote}
\begin{singlespace}
  A long quotation, set tight inside a double-spaced document.
\end{singlespace}
\end{quote}

\parskip\baselineskip 的区别:段间距不是行距

\parskip段落之间额外插入的竖直空白,与行的推进量分开计算。标准类中的默认值是 0.0pt plus 1.0pt——也就是段间基本不加任何空白,只留最多 1pt 的伸缩余地供 LaTeX 平衡页面。原因在于标准类用 首行缩进 而不是空白来标示段落分界。这里的关键是:setspace 完全不碰 \parskip 实测中,施加 \doublespacing 之后 \parskip 仍是 0.0pt plus 1.0pt。所以如果加倍行距之后觉得段落分界不明显,那是 \parskip 的问题,不是行距的问题。

最后说一件不该做的事:不要用 \setlength 直接改写 \baselineskip 本身。 这个长度在每次选择字体时都会被重新设定,你的指定会轻易蒸发。实测:\setlength{\baselineskip}{20pt} 之后,仅仅经过一个 \large 就变成 14.0pt,回到 \normalsize 则是 12.0pt——20pt 一处也没留下。请始终从 倍率 一侧控制行距(\linespread\setstretchsetspace 的声明)。倍率会跟随字号变化,也能让脚注和浮动体的例外处理继续生效。