【注】笔记来自《LaTeX入门》——刘海洋。

1. 简介

图片或表格通常都占有较大的一块,直接放在文档常常会造成分页的困难,即前一页放不下,放在后一页又会造成很大的留白。其他一些大块的内容也可能有类似的问题,比如程序算法、大型公式和不宜断开的特殊形状段落。LaTeX 中通过引入浮动体来解决这类问题。

  • 「浮动体」是一个活动的盒子,它可以把内容放在距离浮动体代码前后不远的地方,通常就是浮动体代码所在地,也可以放在页面开头、末尾或者单独的一页中。

  • 「浮动体」的另一个作用是给图表添加一个标题。LaTeX 的浮动体环境为图表标题提供了专门的命令进行自动编号、自动生成目录的功能,通过第三方宏包还可以对标题格式进行整体设计。

2. 使用

2.1 环境

LaTeX 的标准文档类预定义了两种浮动体环境:figuretable,通常分别用于图和表的排版。figure 环境的语法格式为:

1
2
3
\begin{figure}[<允许位置>]
<任意内容>
\end{figure}

table 环境与之类似。其中可选参数 <允许位置> 用来设定浮动环境可以出现在页面的位置,即 h,t,b,p 四个选项的组合(默认为 tbp):

  • h:此处(here),浮动体的内容被放在代码所在的上下文位置。
  • t:页顶(top),浮动体被放在一页的顶部,这可以是代码环境所在页面或之后的页面。
  • b:页底(bottom),浮动体被放在一页的底部,这可以是代码环境所在页面或之后的页面。
  • p:独立一页(page),一个或多个浮动体被放在单独的页面中,这个页面被称为「浮动页」。与之对应,有正文的页面被称为「文本页」。

比如用选项 hbp 表示允许浮动体出现在环境所在位置、页面底部或单独一页。浮动体允许位置选项的顺序并不重要,LaTeX 总是以 htbp 的顺序尝试放置浮动体。不过单独的一个 h 选项通常并不总能满足,LaTeX 会把它放宽为 ht 两个可能,因此以下三种浮动体环境开头是等价的:

1
2
3
\begin{figure}[ht]
\begin{figure}[th]
\begin{figure}[h]

【注】如果图表较多,最好将浮动图表的位置限定设置得宽松一些,以防止浮动体积压过多,导致最后统一输出。

2.2 应用

浮动体最常见的应用就是直接在 table 环境中放置 tabular 生成的表格,或者在 figure 环境中放置 \includegraphics 命令插入图片。经常还在前面使用 \centering 命令让图表居中放置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
\begin{figure}[htbp]    % 允许在各个位置
\centering
\includegraphics{picture}
\end{figure}
\begin{table} % 默认在页面顶部、底部或单独一页
\centering
\begin{tabular}{|c|c|}
\hline
图形 & \verb=figure= 环境 \\
\hline
表格 & \verb=table= 环境 \\
\hline
\end{tabular}
\end{table}

无论是 figure 环境还是 table 环境,浮动环境的名称和内容并没有必然联系。一个浮动体只是一个与版心等宽的盒子,内容可以任意放置。figure 环境也可以使用 TeX 代码或者是 ASCII 字符画的图形,甚至放置算法、代码或者很长,table 环境中也可以是以插图形式得到的表格,甚至内容可以和名称毫无关系。

2.3 标题

浮动体的另一个重要功能就是使用 \caption 命令加标题,其语法格式为:

1
2
\caption{<标题>}
\caption{<短标题>}{<长标题>}

可选的参数短标题用于图表目录,而交叉引用的标题 \label 需要放在 \caption 后面,或者 <标题><长标题> 中。在 \caption<长标题> 中可以进行长达多段的叙述,但 <短标题> 或单独的 <标题> 中不允许分段。

1
2
3
4
5
6
\begin{figure}[htp]
\centering
\includegraphics{picture}
\caption[图片]{这是一张图片}\label{fig:picture}
% 或者 \caption[图片]{\label{fig:picture}这是一张图片}
\end{figure}

【注】更复杂的标题控制可参见 LaTeX标题控制

2.4 双栏

以上环境都是考虑在单栏文档中,对于双栏或多栏文档,figuretable 环境就成为只占一栏的浮动盒子(宽度是 \columnwidth),其用法与单栏环境相同。

此外,LaTeX 标准文档类还提供了跨栏排版的图表环境 figure*table*,用来产生跨栏排版的浮动体。跨栏浮动体只允许排在页面的顶部(t)或单独的浮动页面(p)中,其他位置参数会被忽略。figure*table* 环境的默认位置都是 tp。在大多数情况下,使用 table*figure* 环境的效果就是把内容排在后面一页的顶部。

3. 详解

尽管环境参数中可以设置位置,但浮动体的位置并不总能令人满意,在图表较多时这个问题尤为明显。

3.1 其他参数

LaTeX 对每个位置的浮动体的总数和占用大小有一定限制,超出限制的浮动体会被排在较后的页面中,但可以在 <允许位置> 选项中增加一个 ! 符号来忽略这些参数限制。因此,在 LaTeX 中最宽松的浮动体位置就是 !htbp。在位置选项中加上 ! 号将使浮动体相对更靠近文字或靠前出现,如果使用这一手段浮动体仍然被排在很靠后的位置,就可能需要将浮动体适当前移一段距离。

! 位置选项相反,\suppressfloats 命令用于禁止浮动体出现在当前页,从而将浮动体的位置向后推。\suppressfloats 命令可以带一个可选参数 tb,表示本页顶部或底部禁止放置浮动体。

  • 限制浮动环境数量和占用大小的参数
参数 类型 默认值 描述
topnumber 计数器 22 文本页顶部浮动体的最大数量
bottomnumber 计数器 11 文本页底部浮动体的最大数量
totalnumber 计数器 33 文本页上所有浮动体的最大数量
dbltopnumber 计数器 22 topnumber 的跨双栏版本
\topfraction 0.70.7 文本页顶部浮动体的最大占用空间比
\bottomfraction 0.30.3 文本页底部浮动体的最大占用空间比
\textfraction 0.20.2 文本页中文本所占的最小空间比例
\floatpagefraction 0.50.5 浮动页中浮动体所占的最小空间比例
\dbltopfraction 0.70.7 \topfraction 的跨双栏版本
\dblfloatfraction 0.50.5 \floatpagefraction 的跨双栏版本
\floatsep 弹性长度 12±212 \pm 2 pt 文本页上,处于页顶或页底的多个浮动体之间的垂直间距
\textfloatset 弹性长度 19±319 \pm 3 pt 文本页上,处于页顶或页底的浮动体与正文之间的垂直间距
\intextsep 弹性长度 12±212 \pm 2 pt 文本页上,使用 h 位置选项排在页面中间的浮动体与上下文之间的垂直间距
\dblfloatset 弹性长度 12±212 \pm 2 pt \floatsep 的跨双栏版本
\dbltextfloatsep 弹性长度 19±319 \pm 3 pt \textfloatsep 的跨双栏版本
1
2
3
4
5
% 设置「限制浮动环境数量和占用大小的参数」示例
\setcounter{topnumber}{4}
\setcounter{bottomnumber}{4}
\renewcommand{\textfraction}{0.15}
\renewcommand{\topfraction}{0.85}
  • 控制浮动页面间距的内部命令(内部命令一般只在宏包或文档类中修改,如果要在正文导言区进行设置,可以在前后分别加上 \makeatletter\makeatother
参数 类型 默认值 描述
\@fptop 弹性长度 00 pt ++ 11 fil 浮动页中页面顶部与浮动体的垂直间距
\@fpsep 弹性长度 88 pt ++ 22 fil 浮动页中多个浮动体之间的垂直间距
\@fpbot 弹性长度 00 pt ++ 11 fil 浮动页中页面底部与浮动体之间的垂直间距

3.2 浮动机制

LaTeX 会把浮动环境做成一个个盒子,所有未输出的浮动体按次序放在队列中处理。LaTeX 所使用的浮动规则可描述为:

  • 浮动体会排在所有位置选项允许的位置中尽可能靠前的地方,但 h 选项优先于 t 选项。总体来说,浮动体的位置选项参数优先级按照 h,t,b,p 的顺序依次降低。
  • 浮动体不会排在比浮动环境所处位置更靠前的页面中。只有在 t 选项生效时,浮动体会排在环境代码位置的同一页更靠前的位置。
  • 对于相同类型的浮动环境,多个浮动体会按次序输出,即当前 figure 不会在更早的 figure 之前输出。但可以在更早的 table 之前输出。特别需要注意的是,双栏文档中,跨栏的 figure*table* 环境和不跨栏的 figuretable 也没有先后制约的关系,因此在双栏环境应该避免混用。
  • 只有浮动体 <允许位置> 可选参数中的位置才会放置浮动体。如果省略这个参数,默认位置参数为 tbp,双栏的跨栏浮动体则是 tp。当仅使用了 h 位置时,LaTeX 会将其扩充为 ht 并发出警告。双栏的跨栏浮动体只有 t,p 选项可以生效,其余选项默认忽略。
  • 浮动体的输出不能造成页面的上溢出。即浮动体输出时,垂直高度不能超过版心的位置。
  • 浮动体的输出必须遵守「3.1」节中的参数限制。但如果 <允许位置> 参数中有 ! 号,有关文本页的限制将被忽略,只有浮动页的限制起效(\floatpagefraction\dblfloatpagefraction
  • LaTeX 最多保存 1818 个未处理的浮动体。如果有过多的浮动体积压不能及时输出,就会报错。通常遇到这种问题只要增加浮动体允许的输出位置参数,或是使用 \clearpage 立即输出所有的浮动体。如果确实要求保留原参数中设定的位置,则可以使用 morefloats 宏包增大保存未处理浮动体的限制。
  • 脚注和边注也是特殊的浮动体,它们的输出位置与普通浮动体不同,但同样具有浮动的效果,会占用未处理的浮动体个数。对于太长而排不下的脚注和边注会排在后面的页面。

上面最后三条规则在遇到 \clearpage\cleardoublepage\end{document} 时会被打破,此时所有队列中未处理的浮动体都会直接输出,<允许位置>p 选项也会打开以保证可以将所有浮动体输出。

【注】由上文的浮动机制可知,双栏文档中带星号跨栏的浮动环境与不带星号的环境不能按顺序输出,这是个 BUG 。

  • 对于使用 LaTex 2e 版本的用户,可以使用 fixltx2e 宏包来修正这个错误。fixltx2e 是对 LaTeX 2e 核心的修正代码,除了双栏浮动体还做了一些其他改进。
  • 对于使用 2015 年之后的 LaTeX 版本的用户,内核已经修复这些 BUG,不再需要额外使用宏包。

4. 扩展

4.1 float 宏包

浮动图表的目的使用浮动的位置来避免糟糕的分页,但如果不在乎因为图表太大而产生的分页,而要求有确定的位置,即要求不使用「浮动」环境。把图表简单地放在 centerquote 等环境中就可以做到这一点。float 宏包为标准的浮动环境提供了一个新的 H 位置选项用来产生没有浮动效果的图表环境,它的使用和一般的浮动环境没有什么区别。

1
2
3
4
5
6
7
8
% 导言区
\usepackage{float}
% ……
\begin{figure}[H]
\centering
\includegraphics[height=1cm]{picture}
\caption{不浮动的图片}
\end{figure}

【注】H(Here)选项不能与 h,t,b,p 等其他位置选项混用。

事实上,使用了 H 选项的 figuretable 环境就不再是一个浮动体,而只是一个前后间距与内容格式都与普通浮动环境相同的一个大盒子。float 宏包提供的 H 选项比用 center 环境和 caption 宏包的 \captionof 命令来模拟普通浮动环境的格式要更准确,也更自然一些。

4.1.1 \newfloat 命令

float 宏包还提供了定义新浮动环境的功能,这是由 \newfloat 命令完成的,其语法格式如下:

1
\newfloat{<环境名>}{<位置>}{<目录文件扩展名>}[<上级计数器>]

其中,<位置> 是浮动环境默认的位置选项,可以使用 h,t,b,p 或单独的 H<目录文件扩展名> 是用于产生与图表目录类似的目录的辅助文件扩展名。而可选的 <上级计数器> 则可以让浮动环境按章节编号。使用 \newfloat 定义了新的浮动体后,一般还要用 \floatname 命令定义这个浮动体的标题标签名。

1
2
3
4
5
6
7
8
9
10
% 导言区
\usepackage{float}
\newfloat{flowchart}{htbp}{loflow}[chapter]
\floatname{flowchart}{流程图}
% 正文
\begin{flowchart}
\centering
\includegraphics{picture}
\caption{这是新的浮动体}
\end{flowchart}

4.1.2 \floatstyle 命令

float 宏包还提供了 \floatstyle{<格式>} 命令,可以使之后用 \newfloat 定义的所有浮动体按指定的格式输出。也可以在后面使用 \restylefloat{<环境名>} 来指定变换原有浮动环境的格式,可选的格式如下:

  • plain:默认格式,它与标准文档类 figuretable 环境的格式基本相同,只是 \caption 产生的标题总在浮动体环境的底部。
  • plaintop:标题在顶部,其余与 plain 格式相同。
  • boxed:浮动体内容在一个线框中,标题在线框下面。
  • ruled:浮动体类似三线表的格式,标题在顶部,标题前后与浮动体后面各有一条横线。
1
2
3
4
5
6
7
8
\floatstyle{ruled}
\restylefloat{flowchart}
% 正文
\begin{flowchart}
\fbox{A} $\longrightarrow$ \fbox{B} \\
\fbox{C} $\longrightarrow$ \fbox{D}
\caption{基本流程图}
\end{flowchart}

【注】使用 float 宏包的 \newfloat\restylefloat 重定义浮动环境中只能使用一个 \caption 标题,标题的位置也固定为顶部或底部,这对于排版并列图表非常不便。caption 宏包个别功能也因此受到影响,ruled 格式中标题格式则完全固定。因此,如果对标题有较高要求,更高的方式是是噢能够 newfloat 宏包的 \DeclareFloatingEnvironment 命令来定义新的浮动体,其语法格式如下:

1
\DeclareFloatingEnvironment[<选项表>]{<环境名>}

其中,<选项表> 可以使用下面的选项:

  • name=<标签名>
  • listname=<目录名>
  • fileext=<目录文件扩展名>(默认是lo<环境名>
  • placement=<位置参数>
  • within=<上级计数器>(可以为 none
  • chapterlistsgaps=onoff(在目录中,设置不同章浮动体标题间是否增加额外间距)

此时,定义流程图的格式可以使用如下命令:

1
2
\usepackage{newfloat}
\DeclareFloatingEnvironment[fileext=loflow,placement=htbp,within=chapter,name=流程图,listname=流程图目录]{flowchart}

使用这种方式定义的新浮动体环境没有标题方面的限制,可以与 caption 更好的结合。并且可以使用 \listof<环境名>s 这样的命令来输出目录,比如前面定义的流程图可以使用 \listofflowcharts 来输出目录。

4.1.3 \floatplacement 命令

float 宏包的 \floatplacement 可以重定义浮动环境的默认位置参数,比如让图表环境都允许 h 位置:

1
2
\floatplacement{figure}{htbp}
\floatplacement{table}{htbp}

4.1.4 \listof 命令

float 中的 \listof{<环境名>}{<标题>} 命令的功能与命令 \listoffigures\listoftables 类似,用来输出新定义的浮动环境的标题目录:

1
\listof{flowchart}{流程图目录}

4.2 placeins 宏包

placeins 宏包提供了一个 \FloatBarrier 命令,它会在所在的位置产生一个无形的屏障,所有之前的浮动体都必须在这个屏障之前输出。\FloatBarrier 命令的功能类似 \clearpage,不过只要可能,\FloatBarrier 命令会避免直接分页。placeins 宏包有几个选项:

  • section 选项会在每个 \section 命令之前隐含地增加一个 \FloatBarrier 命令,使浮动体局限在一节的范围之内。
  • abovebelow 选项可以放宽 \FloatBarrier 命令的位置限制,使浮动体可以出现在同一页的较前或较后的位置。

4.3 afterpage 宏包

float 宏包的 H 选项给出了确切的「此处」位置,也可以使用 afterpage 宏包来得到确切的「下一页顶部」位置。afterpage 宏包提供了一个 \afterpage 命令,可以把参数中的内容放在下一页的开头,同时不影响正常的正文流向。因此,可以使用以下代码来得到下一页顶部的浮动图表环境:

1
2
3
4
5
6
% 导言区
\usepackage{afterpage}
% ……
\afterpage{\begin{figure}[H]
% ……
\end{figure}}

而如果使用以下代码则会产生与 placeins\FloatBarrier 有类似的效果,它强制所有浮动体在下一页之前输出完毕:

1
2
3
4
5
% 导言区
\usepackage{afterpage}
% ……
\afterpage{\clearpage}
% 或 \afterpage{\FloatBarrier}

4.4 endfloat 宏包

有些期刊会要求稿件将所有的图表放在整个文章的末尾,但把整个浮动环境挪到文档末尾却非常不方便修改,endfloat 宏包就解决了这个问题。引用 endfloat 宏包后,所有的浮动图表都会被放在文档最后。也可以使用 \processdelayedfloats 命令直接输出之前延迟输出的浮动图表,比如放在文档正文之后,参考文献列表之前。