浮动体与放置

图没有出现在你写它的位置;表格跳到了几页之后。这不是 LaTeX 的 bug,而是因为 figuretable浮动体(floating objects)。LaTeX 会把图表从正文流中分离出来,让它们“浮动”到页面版式最合适的位置。本页依次说明你能在多大程度上控制这种位置:[htbp] 中的 位置指定符、阻断浮动流的 \FloatBarrier\clearpage、并排放置两幅图的方法,以及让正文环绕图片的 wrapfig 宏包。

什么是浮动体

图或表跨过分页时会显得很难看;不能这一页放一半,下一页再放剩下的一半。因此 LaTeX 会把每个图表当作一个 整体盒子,在排好一段正文之后,自动为它选择位置:页面顶部、页面底部,或者只放浮动体的专用页。这就是浮动体。标准的浮动环境有 figuretable 两个,分别用于图和表。

浮动体有好处,也有让人困惑的一面。好处是:图表不会被分页切开,编号(“Figure 1”、“Table 2”)以及通过 \caption\label\ref 进行的交叉引用都会自动保持一致。让人困惑的是:写在源码中的位置和实际输出位置会不同。LaTeX 的设计基于这样一个思路:既然正文里可以用 \ref{fig:foo} 写出“见 Figure 1”,图本身就不必紧挨着那句话。所以原则是 按编号引用,而不是按位置指示。用 \input 组织文件以及图像本身的制作放在其他页面讲;这里专注于浮动体最终落在哪里。

[htbp] 位置指定符

figuretable 环境可以接收一个称为 位置指定符(placement specifier)的可选参数:像 \begin{figure}[htbp] 这样写在方括号中,用来告诉 LaTeX 可以使用哪些位置。可组合的字母如下。

指定符含义备注
hhere靠近正文中的当前位置。不能单独使用 h;LaTeX 会自动补上 t
ttop文本页顶部
bbottom文本页底部
ppage单独的浮动页,只放浮动体,没有正文
!override仅对这个浮动体忽略数量限制和浮动体/正文比例限制
H真正就在这里(不浮动)由 float 宏包提供;固定在原处,不再浮动

如果省略指定符,articlebook 等类会使用默认的 tbp(注意没有 h)。写多个字母时,LaTeX 会在这些允许位置中寻找能放下的地方。有两个重要陷阱。第一,单独的 h 基本会被忽略:LaTeX 不允许裸 h,会悄悄补上 t,所以写 [h] 也常常会跳到页顶。真正需要“就在这里”时,请使用后面介绍的 float 宏包提供的 [H]

第二,指定符中字母的顺序不会改变 LaTeX 尝试位置的顺序。无论写 [bt] 还是 [tb],LaTeX 尝试候选位置的顺序都相同(大致是当前位置 → 顶部 → 底部 → 浮动页)。把这些字母理解为允许位置的*集合*即可。LaTeX 还会按浮动体在 源码中出现的顺序 处理,因此后面的图也可能越过前面的图先出现。实际使用时不要限制得太死:像 [tbp][htbp] 这样允许的范围越宽,LaTeX 越容易把浮动体放在附近。缩小到单个字母(尤其是 [h])反而容易漂得更远。

latex
\begin{figure}[htbp]
  \centering
  \includegraphics[width=0.6\textwidth]{plot}
  \caption{実験結果}
  \label{fig:result}
\end{figure}

図~\ref{fig:result} に結果を示す。

在这个例子中,[htbp] 允许当前位置、页顶、页底或浮动页中的任意位置,由 LaTeX 选择最佳位置。用于居中图片的 \centering、用于标题和编号的 \caption、用于引用的 \label,都是浮动体中常见的内容。正文用 図~\ref{fig:result} 按编号 引用它,所以即使图片输出在稍远的位置,文字也仍然成立(~ 是不换行空格,用来避免词和编号在行尾分开)。

强制就在这里 — [H]

如果确实必须让浮动体“就在我写的位置”,请在导言区加载 float 宏包,并使用大写 [H][H] 不是普通的位置字母:它会完全关闭浮动,把图或表 固定 在当前位置。它的行为基本就像在那里直接放下一个大盒子。

latex
\usepackage{float}
% ...
\begin{figure}[H]
  \centering
  \includegraphics[width=0.6\textwidth]{diagram}
  \caption{処理の流れ}
\end{figure}

不过应把 [H] 当作最后手段。固定浮动体时,如果页脚放不下,可能会留下 大片空白,或者把浮动体推到下一页页首,使当前页底部变空。通常信任 LaTeX,并用较宽松的 [htbp],结果反而更整洁。[H] 只适合那些确实必须出现在正文某个精确位置的小图表,例如步骤说明图。也可以用 \floatplacement{figure}{H}[H] 设为全文默认,但基于上述原因并不推荐。

阻断浮动流 — \FloatBarrier\clearpage

最让人头疼的浮动体问题,是某一节的图放不进本节,结果 漂到下一节(或下一章)。当第 2 节的 Figure 3 出现在第 3 节正文中间时,读者会很困惑。要阻止这种情况,需要放置一个浮动体不能越过的 屏障(barrier)。

这个屏障就是 placeins 宏包提供的 \FloatBarrier。在放置这条命令的位置,所有尚未处理的浮动体都会先在它之前输出,之后的浮动体也不能越过它。若想按节隔开浮动体,可以在每个 \section 前写 \FloatBarrier,或者加载 \usepackage[section]{placeins},让它自动在每个 \section 开头插入屏障。

latex
\usepackage{placeins}
% ...
\section{実験}
% ... 図や表 ...
\FloatBarrier   % ここより先へフロートを越えさせない
\section{考察}

\clearpage 与它相近但并不相同,差别在于是否分页。\clearpage输出所有待处理浮动体,然后开始新页;而 \FloatBarrier 只输出浮动体,不强制分页。因此若只想在同一页内设置屏障,用 \FloatBarrier;若在章末等位置可以整页分开,用 \clearpage[section] 屏障默认很严格,会禁止浮动体稍微超出本节范围;可用 [above][below] 选项放宽。

再深入一点,LaTeX 的自动放置会遵循一组 浮动体放置参数:这些内部数值以比例表示,决定页面中允许由浮动体占据多少部分。当其他方法都不奏效时,可以用它们做最后调整(不过多数情况下应先重新检查 [htbp])。

参数默认值含义
\topfraction0.7页面顶部可由浮动体占据的最大比例
\bottomfraction0.3页面底部可由浮动体占据的最大比例
\textfraction0.2文本页中必须保留为正文的最小比例
\floatpagefraction0.5生成独立浮动页所需的最小填充比例
topnumber2页面顶部最多可放置的浮动体数
bottomnumber1页面底部最多可放置的浮动体数
totalnumber3单页最多可放置的浮动体数

比例参数可用 \renewcommand{\topfraction}{0.85} 修改,整数计数器可用 \setcounter{totalnumber}{5} 修改。例如提高 \topfraction、降低 \textfraction,就能让页面顶部容纳更多图表,减少“这里放不下,所以推到下一页”的情况。前面提到的 ! 指定符实际上就是这种调节的局部版本:它告诉 LaTeX 仅对这一个浮动体忽略这些限制。

并排放置两个对象

经常会想把两幅图(或两个表)左右并排。由于浮动体内部可以放任意内容,基本思路是 在一个 figure 中放两个并排的盒子。只用原生 LaTeX 的做法是 minipage;如果要给子图编号为 (a)、(b),则使用 subcaption 宏包。

minipage 是创建指定宽度“小页面”的环境。把两个 minipage 横向放置,并在中间插入 \hfill(可伸缩的水平空白),它们就会分布到左右两侧。诀窍是把每个宽度设为略小于正文宽度的一半,例如 0.48\textwidth,使总宽度略低于全文宽。

latex
\begin{figure}[htbp]
  \centering
  \begin{minipage}{0.48\textwidth}
    \centering
    \includegraphics[width=\linewidth]{left}
    \caption{左の図}
    \label{fig:left}
  \end{minipage}
  \hfill
  \begin{minipage}{0.48\textwidth}
    \centering
    \includegraphics[width=\linewidth]{right}
    \caption{右の図}
    \label{fig:right}
  \end{minipage}
\end{figure}

在这个例子中,两个宽度为 0.48\textwidthminipage 位于 figure 内部,中间的 \hfill 把剩余空白向外推,使它们贴近两侧边界。在每个 minipage 内,\linewidth 表示该 minipage 的宽度,所以 \includegraphics[width=\linewidth] 会让图片填满盒子。由于每个 minipage 都有自己的 \caption,它们会得到 不同编号,如 “Figure 1”、“Figure 2”。如果想把这对图当作一幅图,只在 figure 直属位置放一个 \caption

如果要把左右两幅编号为 同一幅图的子图,如 “Figure 2(a)”、“Figure 2(b)”,请使用 subcaption 宏包的 subfigure 环境(写法很像 minipage,内部的 \subcaption\caption 会生成 (a)/(b) 标签)。子图和 caption 的详细用法见单独的 “Captions & subfigures” 页面。并排放置两个表的思路相同:在每个 minipage 中放一个 tabular

让正文环绕图片 — wrapfig

如果想让正文环绕在小图的一侧,也就是杂志文章中常见的布局,请使用 wrapfig 宏包的 wrapfigure 环境(表格则用 wraptable)。语法如下:

latex
\usepackage{wrapfig}
% ...
\begin{wrapfigure}[12]{r}[34pt]{0.4\textwidth}
  \centering
  \includegraphics[width=0.38\textwidth]{portrait}
  \caption{人物像}
\end{wrapfigure}

它有四个参数,其中两个是必需的。{r}位置(放在哪一侧),最后的 {0.4\textwidth}图的宽度。中间可选的 [12] 是要环绕的 行数,可选的 [34pt]伸出量(overhang),即图向页边距伸出多少。位置字母成对出现:小写表示固定在当前位置,大写表示允许作为浮动体浮动

字母侧边备注
r / Rrightr = 原处,R = 可浮动
l / Lleftl = 原处,L = 可浮动
i / Iinner朝向装订侧;用于 twoside 文档
o / Oouter远离装订侧;用于 twoside 文档

在这个例子中,宽度为 0.4\textwidth 的图放在正文 右侧,接下来的 12 行 从它左边环绕;[34pt] 让它伸入右侧页边距。如果省略行数 [12],wrapfig 会根据图的高度自行估算环绕行数(估算不准、环绕变乱时,显式给出会更稳定)。双面打印时如果希望图放在远离装订的一侧,可使用 o(outer),它会在左右页之间自动切换。

wrapfig 很方便,但也 相当挑剔,因此要记住它的注意事项。手册的大意是:

  • 不要在列表内部、列表前后紧邻处使用。 避免放在 itemizeenumeratedescription 等列表环境内部或它们紧挨着的位置。
  • 不要让它跨过分页。 放置环境时要确保环绕部分不会被分页切开;避开页面边界附近。
  • 不要让标题或大型公式环绕它。 为了版面效果,只让普通正文环绕;节标题和陈列公式效果很差。
  • 最好从段落边界开始,而不是段落中间。minipageparbox 中使用时,还要确保环绕在该组结束前完成。

如果环绕效果不稳定,通常把图稍微缩窄、明确写出行数,或把开始位置移动一个段落就能解决。若仍然排不整齐,放弃 wrapfig,改用普通浮动体([htbp],放在正文上方或下方),最终可能更易读。