下划线是懂排版的人最先劝你放弃的一种修饰,而这并非出于品味上的偏见。打字机没有斜体字模,想标出一个词,唯一的办法是把滑架退回去,在字母下面补打一排下划线;而在送往印厂的手稿上,词底下的一道横线是给排字工人的指令——此处排成斜体。下划线从来就不是一种样式,它只是指代样式的记号。LaTeX 把这段历史继承了两遍:\underline 的真身是数学命令,交给它一个长句,它不会换行,而是径直冲进右侧页边距;而人人都会装来补救的 ulem 宏包,在 CTAN 上对自己用途的说明是——让输出“看起来像是打字机打出来的”。本页讲 LaTeX 里怎么加下划线:\underline、\uline 与 \ul 的分工,ulem 和 soul 的区别,以及什么时候你真正需要的其实是 \emph。
\underline 为什么不换行,反而冲出页边距
因为 \underline 本质上是数学命令,它把参数排进一个不可分割的盒子里。它不需要宏包,正文和公式里都能用,但它的老家是数学模式——$\underline{x}$ 里给变量加的那条线就是它。写在句子里时,LaTeX 会悄悄在参数外围进入数学模式,把整段内容排成一个水平盒子,再在下面画一条线。盒子内部没有任何可以断行的位置,于是当这个短语比版心还宽时,TeX 无处可断,只好让它一路越过右边距。
% fine for a single short word
This word is \underline{underlined} in running text.
% the box has no break points, so TeX pushes it into the margin
\underline{a phrase far too long to fit on one line of this measure}日志里的症状值得记住,因为它不是报错而是警告:Overfull \hbox (…pt too wide) in paragraph at lines …,随之打印出的片段形如 []$[]$。那两个美元符号就是最好的证据——LaTeX 在自曝:为了画那条线,它把你的句子裹进了数学模式。另一处更不显眼的毛病是线的位置。\underline 不看上方的字形,直接把线放在固定深度上,所以遇到带下伸部的 g、p,线看上去像是从字里穿过去的。
于是分工就清楚了:\underline 留给数学——它的参数本来就是一个符号,而且待在公式里;一旦这条线要落在句子中,就该换宏包。承担这项工作的宏包有两个,而且并不互相替代。ulem 提供可跨行的下划线与删除线,soul 提供荧光笔和字距调整。不过在装任何一个之前,先弄清下划线本来意味着什么是值得的,因为这往往就决定了你到底需不需要它。
为什么排版行家劝你别用下划线
因为下划线是代用品,而它所代替的东西就在你的键盘上。打字机没有粗体也没有斜体,想标出一个词,唯一的办法就是把滑架退回去,在已经打好的字母底下补打下划线。在印刷行业里,同样一道线还兼着另一份差事:在做过标注的打字稿上,下划线是给排字工人的指令。词底下一道直线表示排斜体,波浪线表示粗体,两道线表示小型大写,三道线表示全大写。作者画线,是因为作者排不出斜体;能排的排字工人读懂那道线,然后把它扔掉。
所以下划线在软件里活了下来,却从排版教科书里消失了:文字处理软件原样继承了打字机的键位,而铅字排版本来就没有“下划线”这个选项。LaTeX 这边的工具也不讳言这一血统。Donald Arseneau 的 ulem 版权声明从 1989 年起算,CTAN 上对它的介绍写着,把 \em 和 \emph 换成下划线是“为了让输出看起来像是打字机打出来的”,而它的手册说它适合“在投给出版社的稿件中需要加下划线”的文字。ulem 不是为了装点一份成品 PDF 而写的,它是为了产出一份打字稿。
实用的准则由此而来。如果只是想让读者在某个词上停一下,就写 \emph{...},把强调长什么样交给文档类去决定:多数类里是斜体,而且当强调嵌套在强调里时会正确地切回正体。真正的下划线留给那些线本身携带信息、而不是语气的场合:校样中的删除、签名栏、待填的空格、链接。下文都默认你有这一类理由。
ulem:能跨行断开的下划线和删除线
载入 \usepackage[normalem]{ulem},把原来写 \underline{...} 的地方改成 \uline{...}:这条线现在会在行尾断开,会穿过词间空白延伸,词内断字也不成问题。这个宏包备齐了校对符号的整套词汇——双线、波浪线、贯穿词的横线、斜向的划销、虚线、点线——因为一份做了标注的稿件需要的正是这套词汇。在数学模式里,\uline 会悄悄把活儿交还给 \underline,所以到处用都安全。
| 命令 | 画出的线 |
|---|---|
\uline | 下划线,可在行尾断开 |
\uuline | 双下划线;校对符号中表示小型大写 |
\uwave | 波浪下划线;校对符号中表示粗体 |
\sout | 删除线,横穿词的中央 |
\xout | 划销:用重复的 / 覆盖文字 |
\dashuline | 虚线下划线 |
\dotuline | 点线下划线 |
控制这条线的参数有两个,而它们的设置方式不同,这一点最容易让人栽跟头。\ULthickness 是线宽,默认 .4pt,但它是宏而不是长度,所以要写 \renewcommand{\ULthickness}{0.8pt},\setlength 对它无效。\ULdepth 是从基线到线的下落量,这是真正的长度,用 \setlength 设定;默认值是标志量 \maxdimen,它告诉 ulem 改为根据当前字体推算深度。这两个旋钮解释的东西比看上去多得多:\sout 的定义无非就是把 \ULdepth 设为 -.55ex 的下划线。深度取负,线就从基线抬起来,正好从词的中间穿过——在 ulem 里,删除线其实是一条故意画错位置的下划线。\xout 更直白,它只是用重复的 / 把文字盖住。
\usepackage[normalem]{ulem}
\renewcommand{\ULthickness}{0.8pt} % a macro, so \renewcommand
\setlength{\ULdepth}{1.8pt} % a length, so \setlength
\uline{important} \uuline{urgent} \uwave{boat}
\sout{wrong} \xout{removed}
\dashuline{dashing} \dotuline{dotty}\emph 突然变成下划线:normalem 选项
因为只写 \usepackage{ulem} 会重新定义强调,而手册对此毫不掩饰:“In LaTeX ulem replaces italics with underlining in text emphasized by \em or \emph”。这不是缺陷,而是这个宏包本来的用途——别忘了它是为产出什么而写的。但后果是:一份两百页里一直安稳使用 \emph 的文档,只因为要给一个词加下划线而载入这个宏包,所有强调处就都长出了横线。嵌套时更糟:普通的 \emph 会在嵌套时于斜体与正体之间来回切换,而 ulem 版按手册的说法是“generates multiple underlining; it does not alternate on and off”——线只会一层层叠加。
解法只是选项里的一个词:\usepackage[normalem]{ulem}。强调随即恢复常态,横线只出现在你明确写下 \uline 及其同族的地方。同样的开关也有声明形式——\normalem 关掉替换,\ULforem 再打开——所以如果你真的在准备一份打字稿,可以在文中随时切换。实务上,除非你能把理由说出口,否则每次都请带着 [normalem] 载入 ulem。
\usepackage[normalem]{ulem}
% \emph keeps its italics; a rule appears only where you ask for one
This is \emph{emphasis}, and this is \uline{underlined}.
% \ULforem brings the substitution back, \normalem switches it off againsoul:用 \hl 做荧光笔,用 \so 拉开字距
如果你要的是一支黄色荧光笔,或是为了强调而拉开的字距,那么该用的宏包是 soul——而它走的是另一条完全不同的路。它把文本交给 TeX 的断字机制,取回音节和字符,然后在它们之间的缝隙里动手。正因如此,它才能一边把词的字距拉开,一边还允许在词中间断行。作者 Melchior Franz 在手册里抢先掐灭了关于名字的那个显而易见的猜测:“the package name soul is only a combination of the two macro names \so (space out) and \ul (underline)—nothing poetic at all”。如今由 Oberdiek Package Support Group 维护;从第 3 版起它已并入旧的 soulutf8,UTF-8 输入无需再额外载入什么。
| 命令 | 效果 |
|---|---|
\so | 字距加宽,把字母之间拉开 |
\caps | 针对大写与小型大写连排调整的字距 |
\ul | 下划线,可跨行断开 |
\st | 删除线(重打覆盖) |
\hl | 荧光笔式高亮;默认黄色,需要 color 或 xcolor |
颜色是逐项设置的:下划线用 \setulcolor,删除线用 \setstcolor,高亮用 \sethlcolor,把参数留空即可关掉着色。默认高亮是黄色,两种线是黑色。有一个陷阱值得明说:只有载入了 color 或 xcolor,\hl 才会着色。 没有它,这条命令会不声不响地退回成下划线,在屏幕上看起来就像高亮根本没出现。自定义色用 \definecolor 定义,再交给 \sethlcolor。
\usepackage{color,soul}
\definecolor{lightblue}{rgb}{.90,.95,1}
\sethlcolor{lightblue}
\so{letterspacing} \ul{underlining} \st{overstriking}
\hl{this is highlighted in light blue}
\ul{Auf{}lage} % {} keeps the fl ligature from forming
\so{foo \mbox{little} bar} % \mbox, not bare braces, around hyphenable text逐字解析这套机制的代价,是参数不再是普通的 LaTeX。soul 必须赶在 TeX 的段落构建之前读完每一个记号,因此有若干写法被禁止——而且失败得很响亮:Package soul error: Reconstruction failed,同时在输出的相应位置留下一个黑方块,好让你在版面上找到出事的地方。值得记住的规矩如下。
- 公式要用
$...$。 用美元符号包起来可以,LaTeX 写法\(...\)不行。 - 花括号用来成组,但不能藏着断点。
\so{foo {little} bar}会报Reconstruction failed,因为组里含有断字位置,而空格也算一个。应写成\so{foo \mbox{little} bar}。 - 不能嵌套。
\ul{foo \so{bar} baz}不允许。若确有需要,先把内层放进盒子,并接受这个盒子不会断行。 - 连字要手动拆开。 在
\ul、\st、\hl内部,于不该成连字的位置插入{}或\null(\ul{Auf{}lage})。 \verb、环境和命令定义都不能放进去。 必须原样通过的内容,可以走\soulomit{...}这条后门。
ulem 与 soul 的区别:该装哪一个
要校对符号就用 ulem,要荧光笔就用 soul;两样都要,就两个都载入——命令名不会冲突,因为 ulem 提供的是 \uline,soul 提供的是 \ul。两者之中 ulem 更宽容:参数里几乎什么都能放,就算断得不好看,好歹会断。soul 把线与字形贴合得更细致,而且同一次载入还附带 \hl 和 \so,但它的参数如上表所示是一门受限的语言。一份需要“划掉这里、给替换词加下划线”的稿子,走 [normalem] 的 ulem 最短;一份需要给审稿人留黄色记号的稿子只有一个候选,因为 ulem 根本没有高亮。
在草稿中标出删除和新增
\sout 和 \uline 最站得住脚的用途,是一份必须展示改动的草稿。但别把画线命令直接写进正文。写下你的意思,让宏去决定它怎么印:带开关的 \deleted{...} 和 \added{...} 只花导言区三行,却省掉投稿前逐个搜寻清除的一整轮。它们还让源码更好读,因为 \deleted{旧的估计值} 说明了一件事,而 \sout{旧的估计值} 什么也没说。
\usepackage[normalem]{ulem}
\newif\ifrevisions
\revisionstrue % final version: \revisionsfalse
\newcommand{\deleted}[1]{\ifrevisions\sout{#1}\fi}
\newcommand{\added}[1]{\ifrevisions\uline{#1}\else #1\fi}
% The estimate was \deleted{0.42} \added{0.51}.有两个习惯能避免翻车。把校对标记和强调分成两套词汇——语气交给 \emph,改动史交给 \deleted 和 \added——这样关掉开关时绝不会碰到正文的意思。另一个是把“关掉开关重排一次,亲眼看看 PDF”写进投稿清单,因为定稿文件里漏下的一条删除线,正属于印出来之前没人会发现的那类事故。
给中日韩文字加下划线,以及标记 PDF 的问题
在下决心之前,有两条限制值得先知道。第一,这两个宏包都是为拉丁文字写的。ulem 和 soul 依靠词、断字位置和词间胶来推理,而一串中文、日文或韩文这三样都不提供,于是一段长长的中日韩下划线往往断在奇怪的地方,或者干脆不断。日文 TeX 圈用自己的宏包回应这一点,常被推荐的是提供 \Underline、\Midline、\Overline 的 jumoline(在 CTAN 之外分发,不含在原装 TeX Live 里)。第二,CTAN 把 ulem 和 soul 都归入“tagged PDF incompatible”这一主题;在 LaTeX 正走向可访问输出的今天,这一点开始要紧。另外,屏幕上漂亮的黄色 \hl,在黑白打印里会变成一片灰糊。这两件事请在截稿之前查,而不是之后。