Overfull \hbox 是警告,不是错误。LaTeX 会一直跑到最后,PDF 也确实生成了——只是其中某一行伸出了右边距。所以第一件该做的事不是盯着日志看,而是打开 PDF 去看那一行。在此基础上,本页依次说明:(71.93637pt too wide) 里的数字量的是什么,in paragraph at lines 4--9 与 detected at line 3 有何区别,\hbadness、\tolerance、\emergencystretch 中究竟该动哪一个,以及为什么「真正修好」和「只是让警告闭嘴」是两件完全不同的事。它的镜像警告 Underfull \hbox,以及纵向的 Overfull \vbox,同样归本页管。
(71.93637pt too wide) 里的数字量的是什么
它量的是这一行超出 \hsize(栏宽)的量,单位是点。1pt 约合 0.35mm,所以 0.5pt 肉眼根本看不见,而 70pt 大约是一个拇指宽度地挂在纸面外。仅凭这个数字就能定优先级——只超几点没人会注意到,这也是 LaTeX 默认对 0.1pt 以内保持沉默的原因(\hfuzz=0.1pt)。TeX 是以「盒子」为单位排版的,把一行字符横向排在一起的盒子就是水平盒,即 \hbox。Overfull \hbox 的含义是:分行时某个盒子的内容比栏宽还宽,而且再也压不下去了。行压不下去的原因几乎总是同一个——这一行里没有任何可以断开的地方。
警告的后半段,例如 in paragraph at lines 4--9,告诉你它发生在哪里。这类措辞共有四种,出现哪一种决定了你该去哪里找,所以请用下表对照。表中每一种都是在 TeX Live 2024 的 pdfLaTeX 下用最小文件实测复现的。其中最麻烦的是 has occurred while \output is active,意思是「正在组装页面时」,肇事内容未必对应你写下的任何一行。反方向也有陷阱:裸的 \mbox{...} 与 \makebox[2cm]{...} 无论内容伸出多远,都一条警告也不会给。它们用作填充的 \hss 可以无限收缩,在 TeX 看来盒子总是刚好装下;于是跨过边距的字符就这么印了出来,日志里毫无痕迹。
| 措辞 | 含义 | 该看哪里 |
|---|---|---|
in paragraph at lines A--B | 发生在普通段落的断行过程中 | 第 A 行到第 B 行的那一段;最常见 |
detected at line N | 发生在固定宽度的显式盒子而非段落中 | 第 N 行的 \hbox to、\makebox[…][s] 或宏包生成的盒子 |
in alignment at lines A--B | 发生在表格对齐中 | tabular*、tabularx 等指定了宽度的表格 |
while \output is active | 发生在组装页面的过程中 | 页眉、页脚、脚注、浮动体;行号不可靠 |
日志会把肇事的那一行给你看——连断字点都标出来
警告正下方,TeX 会把伸出去的那一行内容原样打印出来,而且在它找到的每个断字点插入 -。这正是诊断的关键。下面是把英文灌进 4cm 宽栏时的真实日志:Wis-senschaft-skol-leg 带着连字符,而 electroencephalography- 一个都没有。TeX 会把含有显式连字符的词排除在自动断字之外(扫描在显式连字符处停止)。也就是说这一行确实无处可断,\tolerance 调多高都没用。看日志里的连字符,就能一眼判断断字究竟是在尝试,还是已经彻底放弃——若整行一个连字符都没有,那多半是语言设置错了。
Overfull \hbox (13.35585pt too wide) in paragraph at lines 4--9
\OT1/cmr/m/n/10 The Wis-senschaft-skol-leg pub-
[]
Overfull \hbox (80.27266pt too wide) in paragraph at lines 4--9
\OT1/cmr/m/n/10 li-ca-tion de-scribes an electroencephalography-
[]想在 PDF 上用眼睛确认位置,就给文档类加上 draft 选项。article.cls 里写着 \DeclareOption{draft}{\setlength\overfullrule{5pt}},它会在每一行伸出的位置右侧画一条 5pt 宽的黑色标记。平时看不到这些黑条,是因为 latex.ltx 最后执行了 \overfullrule 0pt,抵消了 INITEX 默认的 5pt。也就是说,黑条只是被关掉了,随时可以打开:如果不想动类选项,在导言区直接写 \overfullrule=5pt 效果相同——记得提交前删掉。
双栏、表格与代码:窄栏为何盛产 overfull
因为栏越窄,不可断词的相对长度就越致命。 在 10cm 宽的栏里,一个 3cm 的词只占行的三分之一;而在 4cm 宽的栏里,它比整行还长,怎么断都必然溢出。同一份稿子一改成双栏就冒出几十条警告,不是文章变差了,而是栏宽减半了。下面这些地方是 overfull 的高发区,若有印象请先从那里查起。认清「窄栏才是病因」会改变对策——与其到处撒 \sloppy,不如重新审视那张表的 p{} 列宽,往往更快。
- 双栏排版(
\documentclass[twocolumn]、multicol)。栏宽大致减半,原本在单栏下没问题的词会一齐溢出。 - 表格的
p{}、m{}、b{}列与tabularx。列宽是作者自己定的数值,常常配不上里面要放的内容。 - 逐字环境(
verbatim、\verb、listings)。空格与换行都照原稿保留,TeX 根本没有断行的余地。 - URL、DOI、文件路径、型号、化学名、基因名。 不含空格的长字符串会被当作一个词。
- 行内公式。 默认情况下公式只能在二元运算符或关系符之后断开,在
\frac之类结构内部则完全不能断。 - 脚注与图表标题。 它们有时以比正文更窄的宽度排版,容易以
\output is active的形式被报出。
消除 overfull hbox:从最优先的做法开始
改写一个词是最好的对策。 这个答案不够花哨,却是任何软件都替代不了的解决办法,而且通常只要五秒钟:把长词换成短的同义词、调整语序、把冗长的型号挪进脚注——盒子就装下了。这个排序是有道理的。TeX 的断行算法一次考察整个段落(高德纳与迈克尔·普拉斯 1981 年论文《Breaking Paragraphs into Lines》),所以改动段落最后一个词,可能连第一行的断法都会变。反过来说,作者挪动一个词,就能大幅拓宽排版的回旋余地。下面按效果与副作用的平衡排列各种对策。
- 改写。 通常改一个词就够,且毫无副作用。冗长的型号与产品名该放进脚注或表格。
- 确认语言设置。 德语或法语正文若套用英语断字规则,就找不到可断之处。用
babel写\usepackage[ngerman]{babel};在 XeLaTeX/LuaLaTeX 下用polyglossia的\setmainlanguage{german}。 - 让那个词能断开。 在词中放
\-即可选连字符;\hyphenation{Wis-sen-schafts-kol-leg}在导言区登记例外。对已含显式连字符的复合词,在连字符后插入\hspace{0pt}可重新创造断点。 \sloppy或sloppypar环境。 以段落为单位放宽词间距。sloppypar作为环境会在\end处收束,比\sloppy更安全。- 调高
\emergencystretch。 实测中仅\emergencystretch=3em就把 5 个 overfull 变成 0 个(代价是多出 7 个 underfull)。副作用是词间距变松,远不如文字挂出页面显眼。 - 加载
microtype。 细微的字符突出与字宽伸缩,在同一测试中把超出量从 13.4pt 降到 8.9pt、从 80.3pt 降到 74.9pt。注意它是减少而不是消除。 - 最后手段:
\linebreak或\mbox。 手工指定断点。之后一改句子位置就错,所以只留给交稿前的最终微调。
\tolerance、\emergencystretch、\hbadness、\hfuzz 各管什么
前两个改变排版本身,后两个只改变警告的出现方式。 混淆这一区别,就会出现「以为修好了,其实只是藏起来」的事故:把 \hfuzz 调大,超宽报告确实消失,但纸面上的文字一毫米都没动。TeX 的断行最多分三轮:先在 \pretolerance 范围内不用断字试一次,不行就在 \tolerance 范围内加断字再试,还不行就把 \emergencystretch 的额外伸展量加到每一行上做第三轮。\emergencystretch 只在第三轮起作用,这正是它的定位——山穷水尽时才打出的最后一张牌。LaTeX 的默认值写在 latex.ltx 里:\tolerance=200、\hbadness=1000、\hfuzz=0.1pt。常用的 \sloppy 也在同一个文件中,其真身只有四条赋值:\tolerance 9999、\emergencystretch 3em、\hfuzz .5pt、\vfuzz\hfuzz。所以 \sloppy 并不只是「提高容忍度」,它同时设置了 \emergencystretch——实测中,单独的 \emergencystretch=3em 与 \sloppy 结果完全相同。
| 参数 | LaTeX 默认值 | 作用 |
|---|---|---|
\tolerance | 200 | 一行可接受的最大劣度;调高会改变排版结果 |
\emergencystretch | 0pt | 仅在第三轮加入的额外伸展量;会改变排版 |
\hbadness | 1000 | 只有劣于此值的行才报 underfull。输出不变 |
\hfuzz | 0.1pt | 不超过此值的溢出不予报告。输出不变 |
\overfullrule | 0pt | 在溢出行旁绘制的黑条宽度;draft 会设为 5pt |
% changes the typesetting -- use these to actually fix boxes
\emergencystretch=3em % last-resort stretch on the third pass
\usepackage{microtype} % protrusion and font expansion
% changes only the log -- the page looks exactly the same
\hbadness=10000 % never report Underfull \hbox
\hfuzz=1pt % ignore overhangs below 1pt当长 URL 与代码字符串死活不断行
光用 \url{} 包起来常常不够。 在 5cm 宽的栏中实测:裸文本形式的长 URL 溢出 79.0pt;改用 url 宏包的 \url{} 之后仍剩两个盒子,分别是 42.4pt 与 10.8pt。\url{} 只在 /、. 之类字符之后断开,因此无法在主机名或长路径片段的中间断行。真正管用的有两招:一是配合 \sloppy,实测 overfull 归零,换来的是 underfull——\sloppy 一贯附带的词间距变松就是代价;二是 xurl 宏包,只加一行 \usepackage{xurl} 就做到 overfull 与 underfull 都为 0,因为 xurl 允许在 URL 的任意位置断开。hyperref 内部会加载 url,断行行为相同;要让链接本身跨行断开则需要 breaklinks 选项。对代码清单而言,对应的开关是 listings 的 breaklines=true。
\usepackage{hyperref} % loads url internally; add breaklinks for split links
\usepackage{xurl} % allows a break at any point inside a URL
...
\url{https://example.org/proceedings/vol12/paper-0037.pdf}Underfull \hbox (badness N) 是相反的症状
某一行不够宽,TeX 只好把词间距拉大来填满——这就是 Underfull \hbox。它是两者中较不紧急的,badness 数值可作判断依据。badness 从 0(完美)到 10000(上限,「不能更差了」)。实测中也会出现 1590、2050、7667 这样的中间值,但当一连串 badness 10000 出现时,词间距必定已经肉眼可见地变宽,请去看 PDF。最常见的成因是追杀 overfull 的副作用:\sloppy 或 \emergencystretch 会把 overfull 换成 underfull(上文实测中 5 个变 0 个,同时冒出 7 个 underfull)。另一种成因是在段落中间用 \linebreak 或 \\ 强行制造短行。\linebreak 的含义是「在此断行,但仍要填满行宽」,所以词距会被拉开;\newline 与 \\ 的含义是「这一行到此为止」,因此不会。想要一个刻意的短行,就用 \\。 若只想让消息消失,\hbadness=10000 可以做到,而纸面分毫不变。
Overfull \vbox (… too high) 与 Underfull \vbox
同一套逻辑也存在于纵向,只是把「宽度」换成了「高度」。 Overfull \vbox (56.90552pt too high) 意思是内容装不进一个固定高度的纵向盒子。实测中,像 \vbox to 1cm{\hrule height 3cm} 这样的显式盒子会以 detected at line 3 的形式报出。实际文档里更常遇到的是在组装页面时:放入一个比 \textheight 还高的图或 \rule,就得到了 Overfull \vbox (85.35828pt too high) has occurred while \output is active。看到这种形式,第一个该怀疑的就是大到一页放不下的插图。Underfull \vbox (badness 10000) 则相反——纵向的弹性空白被拉伸以填满高度。在 \flushbottom(book 类的默认)下,为了对齐每页底端会拉伸纵向空白,所以内容稀少的页面很容易触发。若不在意,可改用 \raggedbottom,或用 \vbadness 与 \vfuzz 提高报告阈值——同样地,提高阈值不会改变纸面分毫。当插图确实放不下时,\enlargethispage 可以只为该页拉长正文区域。