交叉引用

“参见图 3”“由公式 (2)”“见第 2 页”——如果手写这些编号和页码,只要移动一个图、表或小节,所有引用都会错位。LaTeX 的做法是给对象贴上名称,让机器计数。本页从核心的 \label\ref/\pageref 开始,经过 amsmath 的 \eqref、hyperref 的 \autoref\nameref,再到 varioref 与 cleveref,依次介绍能让引用自动保持正确的工具。

核心机制 — \label 与 \ref

整个相互引用系统只建立在两个命令上。\label{key} 会把名称 key 绑定到该位置最近一次递增的计数器的值。\ref{key} 则把这个名称指向的编号插入正文。编号由 LaTeX 计数,所以你完全不需要自己输入数字。key 是你自选的任意字符串,也就是源码中指代图、公式或小节的“昵称”。

关键在于“最近一次递增”的说法:\label 捕获什么,取决于它放在哪里。图或表应放在 \caption 之后(递增计数器的是 \caption;若放在 \begin{figure} 之后,可能会捕获章号等);公式应放在 equation 环境内部;标题应放在 \section 等命令之后。经验法则是:把 \label 紧跟在产生编号的命令后面。

latex
\section{はじめに}
\label{sec:intro}

\begin{equation}
  \label{eq:euler}
  e^{i\pi} + 1 = 0
\end{equation}

\begin{figure}
  \centering
  \includegraphics{leaf}
  \caption{葉脈の構造}
  \label{fig:leaf}
\end{figure}\ref{sec:intro}節で述べたように、式~\ref{eq:euler}と図~\ref{fig:leaf}を参照する。

\ref 只返回编号,因此“图”“公式”“节”等词需要自己写。惯例是用不可断空格 ~(tie)把词和编号连接起来,而不是普通空格,这样换行时词不会和编号分离(例如 Figure~\ref{fig:leaf})。后面介绍的 \autoref\cref 正是用来消除这种手写词语的麻烦以及写错类型的风险。

为什么要编译两次

相互引用无法在一次编译中确定。LaTeX 每遇到一个 \label,都会把对应编号和页码写入 .aux 文件(与正文同名的辅助文件)。\ref 能使用的是上一次运行写入 .aux 的信息。因此第一次处理时目标编号还未知,输出中会出现粗体 ??,日志中也会给出下面的警告。

latex
LaTeX Warning: Label(s) may have changed. Rerun to get cross references right.

再编译一次后,.aux 中的值会被读回,?? 会变成正确编号。如果编号发生前后移动导致引用值改变,警告会再次出现,因此需要重复到警告消失为止(实际工作中通常两次足够)。latexmk 等构建工具会自动执行这个循环;Overleaf 也会在后台多次处理,所以你很少在那里看到 ??

页码引用与命名

如果想引用的不是编号而是页码,使用 \pageref{key}。它接受与 \ref 相同的名称,并返回该 \label 所在页面的页码。这样就能同时写出编号和页码,例如“see Figure 3 on page 12”(Figure~\ref{fig:leaf} on page~\pageref{fig:leaf})。

key 可以是任何字符串,但广泛使用的做法是给它加上表示类型的前缀sec:(节)、fig:(图)、tab:(表)、eq:(公式)、ch:(章)、lst:(代码清单)。这样有两个好处。像 fig:leaf 这样按含义命名,即使调整图片顺序也不必改标签名。并且一看 \ref{fig:...} 就知道目标类型,也能避免 caption 和代码清单的名称冲突。

前缀用于
ch:
sec:节和小节
fig:
tab:
eq:公式
lst:代码清单

公式引用 — \eqref(amsmath)

公式编号按惯例写成带括号的形式(“由公式 (3)”)。普通 \ref 只返回 3,需要手动补括号;加载 amsmath 后可用的 \eqref{key}自动补上括号,返回 (3)。更好的是,括号会不受周围字体影响始终以直立体排版,即使在斜体文本中也不会倾斜。引用公式时,\eqref\ref 更方便。

latex
\usepackage{amsmath}
% ...
式~\eqref{eq:euler}はオイラーの等式である。
% 出力: 式 (1) はオイラーの等式である。

hyperref 扩展 — \autoref 与 \nameref

加载 hyperref 后,每个引用都会在 PDF 中变成可点击链接,并增加两个方便的引用命令。\autoref{key} 会根据目标类型自动在前面加上对应词,如 “Figure”“section”等(小节会得到 “section 3.4”,图会得到 “Figure 3”),并把整体做成超链接。这样就不必在 Figure~\ref{...} 中手写 “Figure”,也避免写错类型。前置词可通过重定义 \figureautorefname\sectionautorefname 等来改变,这也是本地化的方法。

另一个命令 \nameref{key} 插入的不是编号,而是目标的标题文字本身。如果对 \section{Introduction} 上的标签使用 \nameref,就会得到 “Introduction” 这个标题文本。当你想按标题而不是编号引用时使用它,例如“as discussed in ‘Introduction.’”。

latex
\usepackage{hyperref}
% ...
\autoref{fig:leaf}を参照。   % 出力: Figure 3 を参照。(リンク付き)
\nameref{sec:intro}で述べた。 % 出力: はじめに で述べた。

感知页码的引用 — varioref

在装订文档中,与其机械地写“第 N 页的图”,若距离很近,说“下一页的图”,若在同一跨页,说“对页的图”,读起来更自然。varioref\vref{key} 会像 \ref 一样输出编号,同时检查目标是否在另一页,并自动添加与页位置相关的文字,如 “on the next page”“on the facing page”“on page 5”。如果目标在同一页,则不添加任何内容。

如果只想给出页码提示,使用 \vpageref{key}(不输出编号,只输出“on the next page”等)。\vpageref 有两个可选参数:第一个指定目标在同一页时使用的文字,第二个指定目标不在同一页时的引导语。当引用和目标很近、可能会也可能不会被分页隔开时,这很有用。由于输出会随页面位置动态变化,varioref 通常可能需要额外一次编译才能稳定。

latex
\usepackage{varioref}
% ...
See~\vref{fig:leaf}.
% 同ページ: See figure 3.
% 別ページ: See figure 3 on the next page.  /  ... on page 12.

智能引用 — cleveref(\cref / \Cref)

cleveref 把引用提升了一个层级。\cref{key}\autoref 一样会自动前置类型词(默认如 “fig. 1”,使用 noabbrev 选项则为 “figure 1”),但它真正的强项是多个引用和范围引用。像 \cref{a,b,c} 这样用逗号分隔且不加空格传入标签时,它会自动排序并压缩编号,输出 “figures 1, 2 and 3” 或 “equations~(2) and~(4)” 等,甚至会正确处理类型词的单复数。连续范围可用 \crefrange{first}{last} 缩成 “figures 1 to 3”。

句首需要类型词大写时,使用 \Cref{key}(首字母大写),用于 “Figure 3 shows …” 这样的开头;句中则用小写的 \cref。如果希望全文始终大写,可用 capitalise 选项加载。前置词可用 \crefname{type}{singular}{plural} 定义或修改(首字母大写版本是 \Crefname),这也是本地化到日语等语言的方法,例如 \crefname{figure}{図}{図}。如果只想像普通 \ref 一样输出编号,使用 \labelcref{key}

加载顺序至关重要cleveref 必须最后加载,并且在 hyperref 之后。如果也使用 varioref,顺序应为 variorefhyperrefcleveref。顺序弄错时,引用可能在日志没有任何警告的情况下指向完全错误的对象

latex
\usepackage{varioref}
\usepackage{hyperref}
\usepackage{cleveref}   % 必ず最後に / always last
% ...
\cref{fig:a,fig:b,fig:c}   % figures 1 to 3
\cref{eq:euler,eq:max}     % equations (1) and (4)
\Cref{sec:intro} discusses % Section 1 discusses ...

如果不确定该用哪个,建议在整个文档中统一使用 cleveref。它会自动处理类型词、单复数、多个引用和范围,因此用 Figure~\ref{...} 方式可能出现的错误,例如想写 Figure 却写成 Table,就不会发生。

命令输出内容
\label{key}给最近的计数器加标签(无输出)
\ref{key}仅编号(如 3)
\pageref{key}该标签所在页码
\eqref{key}带括号的公式编号(如 (3))/ amsmath
\autoref{key}类型词 + 编号 + 链接(如 Figure 3)/ hyperref
\nameref{key}目标标题文本 / hyperref
\vref{key}编号 + 页码提示(下一页等)/ varioref
\cref{key}类型词 + 编号;自动处理列表/范围 / cleveref
\Cref{key}首字母大写的 \cref,用于句首 / cleveref
\crefrange{a}{b}连续范围引用(如 figures 1 to 3)/ cleveref