脚注与边注

LaTeX 的 \footnote 有一个人人都会踩一次的坑:写在 tabular 里的脚注不会输出正文。标记留在表格中,注释内容消失,而且既不报错也不警告。更糟的是,消失的注释仍然占掉一个编号,所以下一条脚注从 3 而不是 2 开始。有趣的是,LaTeX 自己也掉进过这个坑:\maketitle 把作者名排在一个 tabular 里,所以标准文档类会在标题块内悄悄把 \footnote 换成 \thanks。本页实测走一遍 \footnote\footnotemark / \footnotetext 这一对命令、minipage 内的独立编号、用 footmisc 调整、用 \marginparmarginnote 做边注,以及尾注。

脚注基础 — \footnote 的写法与编号形式

\footnote{text},LaTeX 就会在该位置放一个上标编号,并把对应的文字排在该页底部。编号由 footnote 计数器自动递增,无需自己指定。关键在于 放置位置。标记应紧跟被注释的词,所以 \footnote紧接在该词之后,中间不要有空格。词与命令之间若有空格或换行,这个空白会留在正文里,使标记离开该词。与标点的关系上,标记通常放在标点 之后

latex
TeX was born in 1978.\footnote{Written by Donald Knuth.}
Its maths setting is still the reference.\footnote{arXiv accepts LaTeX sources.}

% forced number: does NOT step the footnote counter
See the note above.\footnote[1]{Same note, referenced twice.}

要强制指定编号,写 \footnote[num]{text}。这一次调用不会推进 footnote 计数器,而是使用你给的编号,因此可以让两个位置指向同一条注释。编号的 外观\thefootnote 决定。若要把阿拉伯数字换成符号,使用 \renewcommand{\thefootnote}{\fnsymbol{footnote}}\fnsymbol 把 1–9 映射为星号、短剑号等,适合注释较少的文档。\alph\roman 同理。若要每章重新编号,现在的写法是用 chngcntr\counterwithin*{footnote}{chapter},而不是去动 \@addtoreset

了解决定脚注区外观的几个长度也很有用。在 TeX Live 2024 的 article 中实测:决定注与注之间最小间距的 \footnotesep6.65pt,正文与脚注区之间的空白 \skip\footins9.0pt plus 4.0pt minus 2.0pt。分隔两者的那条短横线是一个宏 \footnoterule,用 \renewcommand{\footnoterule}{} 重定义为空即可去掉它。

表格里的脚注不出现 — tabular、caption 与标题的陷阱

因为 \footnote 只有在「外层段落模式」中才能正常工作tabular 内部处于单元格这一不同的模式,注释正文不会被交给页面的脚注容器(\footins),于是直接丢失。实际排版时,症状完全无声。用 TeX Live 2024 处理下面的文档,pdftotext 输出依次是 Body text.1A value2B value,而页面底部 只出现第 1 条注释。第 2 条的内容无处可寻,日志里也没有任何一行提示。

document.tex
\documentclass{article}
\begin{document}
Body text.\footnote{Real footnote at the page bottom.}

\begin{tabular}{ll}
  A & value\footnote{This footnote is inside a tabular -- the text is lost.} \\
  B & value \\
\end{tabular}

Next.\footnote{This one is numbered 3, not 2.}
\end{document}

容易忽略的是 编号断层。丢失的注释仍会推进计数器,所以写在表格之后的脚注编号是 3 而不是 2。只读正文的人会纳闷「第 2 条去哪了」。同样的限制也适用于 \caption 和分节命令的参数,但那里的症状要响亮得多:\caption{Cap\footnote{...}} 会直接报错停下,先后打印 ! Argument of \@caption has an extra }.! Paragraph ended before \@caption was complete.。因为 \caption 的参数是会被写入表目录的「移动参数」,脆弱的 \footnote 不能不加保护地放在那里。

把标记与正文分开 — \footnotemark、\footnotetext 与 \thanks

出路是 用两条命令分别放置标记和正文。在表格或标题内部,用 \footnotemark 只输出标记;回到正文之后,再用 \footnotetext{…} 写内容。为了让编号不错位,最稳妥的做法是显式配对,如 \footnotemark[7]\footnotetext[7]{…}

  • \footnotemark — 只在当前位置放置标记(编号)。无参数时把 footnote 计数器加 1;\footnotemark[num] 使用该编号而 推进计数器。
  • \footnotetext{text} — 只在页底放置脚注正文。把它写在 \footnotemark 之后、处于外层段落模式的位置;\footnotetext[num]{text} 可以对齐编号。
latex
\begin{tabular}{ll}
  Item A & value\footnotemark[1] \\
  Item B & value \\
\end{tabular}
\footnotetext[1]{This value is provisional.}

这种「把标记与正文分开」的模式已经内置在 LaTeX 本身之中。下面是 latex.ltx\thanks 的定义:它正是一个 \footnotemark 加上一个延后执行的 \footnotetext[当前编号]。而 article.cls\@maketitle 里有一行 \let \footnote \thanks。标题块中的作者名排在 \begin{tabular}[t]{c} 内部,所以在那里用普通的 \footnote 就会丢失正文——文档类抢先一步,在标题内把 \footnote 换成了 \thanks本页开头那个陷阱的规避方法,LaTeX 自己正在使用。

latex.ltx
\DeclareRobustCommand\thanks[1]{\footnotemark
    \protected@xdef\@thanks{\@thanks
        \protect\footnotetext[\the\c@footnote]{#1}}%
}

实务上,附在 \title\author 上的单位、致谢和联系方式,一律写进 \thanks{…}。如果希望它们用符号而不是数字,惯常做法是在 \maketitle 之前写 \renewcommand{\thefootnote}{\fnsymbol{footnote}},并在其后立即恢复。标准文档类会在 \maketitle 末尾执行 \setcounter{footnote}{0},所以正文自己的脚注会重新从 1 开始。

minipage 内的脚注会变成 a、b、c

因为在 minipage 内部,\footnote 会切换到 另一个计数器 mpfootnote,其标记是小写字母。实测中,放进 minipage 的注释排成 a,与正文的 1、2 毫无关系,并且被放在 minipage 的正下方 而不是页面底部。换句话说,minipage 表现得像一个小型的独立页面。若想换回数字,使用 \renewcommand{\thempfootnote}{\arabic{mpfootnote}}

这个特性正好可以用来把表格的注释放在「表格下方」。把 tabular 包进一个 minipage\footnote 就不会消失,而会排在表格正下方——但要接受它 与页面脚注属于不同的编号体系。若想认真处理表注,专用的 threeparttable 宏包(把表格、注释、标题整理成三段结构)或 tabularraytalltblr 环境会给出更整齐的结果。

footmisc — 每页重新编号、改用符号、并成一段

若想更精细地改变标准脚注行为,就载入 \usepackage[options]{footmisc}。TeX Live 2024 附带的是 2023/07/05 的 v6.0f。选项可以组合使用,例如用 [perpage,symbol] 排版,实测得到 第 1 页是 ∗ † ‡,第 2 页又回到 ∗ †——编号重置与符号标记同时生效。

选项效果
perpage每页重置编号,使每一页都从 1 重新开始。
symbol用符号(∗ † ‡ …)而不是数字标注。symbol* 只把正文中的标记改成符号。
bottom即使该页较短,也把脚注压到纸面最底部。
para把多条注释连成一个段落,而不是每条一行。
multiple检测相邻的标记,并在其间加入分隔,使排列整洁。
hang把标记挂到左侧,并让注释的续行悬挂对齐。
flushmargin注释正文不缩进,与版面左边缘对齐。
norule不在正文与注释之间画横线。splitrule 为被拆分的注释提供单独的线条。
stable\footnote 在分节命令等移动参数中也不会出错。
marginal把标记放到版面之外,探入页边空白。
latex
% per-page numbering, notes pushed to the bottom, adjacent marks separated
\usepackage[perpage,bottom,multiple]{footmisc}

% width of the gap between the mark and the note body
\setlength{\footnotemargin}{1.8em}

footmisc 也能伸手到页边。标记与注释正文之间的空隙——也就是脚注自身的左边距——由该宏包提供的长度 \footnotemargin 控制。另有决定与浮动体先后关系的 bottomfloatsabovefloatsbelowfloats,把注释放在版面旁边的 side,以及让注释不作两端对齐的 ragged。完整的选项名可在 footmisc.sty\DeclareOption 各行中看到。

把注放进页边 — \marginpar 与 marginparwidth

要在正文旁边放一条短注,写 \marginpar{text}。它会在你写下它的那一行的高度,以小字排在页边。在双面排版(twoside)中,它会出现在 外侧页边,并在左右页之间自动换边。若要左右使用不同文字,写 \marginpar[left]{right}:方括号中的 [left] 用于注释落在左页边时,花括号中的 {right} 用于落在右页边时。用 \reversemarginpar 可反转出现的一侧,\normalmarginpar 恢复默认。

边注的尺寸由三个长度决定。TeX Live 2024 的实测值如下:articlereport\marginparwidth65ptbook125pt,给 article 加上 twoside 后会跃升到 121pt。正文与边注之间的间隔 \marginparsep11pt,边注彼此推开的最小间距 \marginparpush5pt。65pt 在 10pt 正文下勉强只能容纳六个字符,所以在未改动的 article 中写长边注,几乎必然是一词一行地竖着堆叠。若真要用边注,就得先用 \setlength{\marginparwidth}{...}geometry 重新设计页边。

\marginpar 有很硬的限制。它在内部被当作浮动体处理,所以不能用在 figuretable 内部、脚注内部,或另一个 \marginpar 内部。把它写进 figure 再编译,会以 ! LaTeX Error: Float(s) lost. 中断。它也只能容纳一个段落。此外,当多条边注落在相近的行上时会互相推挤,LaTeX 会移动它们并报告 LaTeX Warning: Marginpar on page 1 moved.。出现这条警告,就意味着某条边注被印在了偏离原本行的位置。

marginnote — 非浮动体的边注,但需要编译两次

若想绕开这些限制,就用 marginnote 宏包的 \marginnote{text}。它不使用浮动体,所以即便在 \marginpar 会以 ! LaTeX Error: Float(s) lost. 崩溃的 figure 内部也能工作——在同一份文档上实测,\marginpar 版本因错误停止,而 \marginnote 版本顺利通过并在页边输出了注释。与 \marginpar 一样,\marginnote[left]{right} 可以区分左右文字,\reversemarginpar 也会被遵守。TeX Live 2024 附带的版本是 1.4b(2018/08/09)。

不过是有代价的。marginnote 不编译两次就什么都不会出现。 第一次运行的日志中并列出现 Package marginnote Info: xpos seems to be \@mn@currxposLaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.,而 PDF 的页边一片空白。因为它是通过交叉引用机制来判断注释该落在哪一侧的。只有跑第二次,页边才会出现文字。

另外,\marginnote 在花括号 之后 还接受第三个参数——竖直方向的偏移。写法是 \marginnote[left]{right}[offset]。实测中,给出 [-3\baselineskip] 的注释落在正文 上方三行,给出 [3\baselineskip] 的落在 下方三行:负值向上,正值向下。这个功能是必需的,因为 \marginnote 只是把注释放在当前行的高度,完全不做碰撞规避,这一点与 \marginpar 不同。注释重叠时,就用这个参数手工散开。\marginnote 也不能跨页断开,所以若想在页边放长文,应当考虑别的版式设计(分栏,或面向侧注的文档类)。

latex
\usepackage{marginnote}
% ...
A note beside the text.\marginnote{This is a margin note.}

% negative offset moves the note up by three lines
Another line.\marginnote{Nudged upwards}[-3\baselineskip]

% marginnote works here; \marginpar would give "Float(s) lost."
\begin{figure}[h]
  Some figure.\marginnote{Inside a float.}
  \caption{A figure with a margin note}
\end{figure}

章末注与书末注 — endnotes 与 enotez

当注释应当 汇总到章末或书末 而不是页底时,需要的是尾注而不是脚注。标准工具是 endnotes 宏包:写 \endnote{text},并在希望汇总注释出现的位置放上 \theendnotes。实测中,写了两条尾注的文档在正文留下 12 两个标记,并在 \theendnotes 的位置输出了标题「Notes」以及其下的两条注释。标题文字由 \notesname 决定。人文类书籍,或注释多到会让版面发黑的文档,通常会选它。

更现代的选择是用 expl3 编写的 enotez,它通过键值选项开放注释分组、标题样式和列表格式等设置。取舍很简单:只是给既有文档添几条注就用 endnotes,需要按章分组或精细设计版式就用 enotez。无论选哪个,都别忘了把注释送到末尾的代价:读者必须在正文与注释之间来回奔波。混用也是允许的——把读者真正需要的注留作脚注,只把纯出处送到末尾。