\usetheme{Madrid}、\usetheme{Warsaw}、\usetheme{Singapore}——LaTeX 的演示幻灯片 class beamer 目前自带 27 个 presentation theme,无一例外全都以城市命名。作者在手册里亲口说明了原因:他起名的点子用光了,而这些城市都是他或某位合作者参加过会议或研讨会的地方。这份随意其实也是整个 class 的性格。写 beamer 几乎和写任何别的 LaTeX 文档一样,只有一点不同,而这一点改变了一切:单位是 frame,不是页。本页就从这一点出发,依次讲 frame、overlay、主题,以及为什么一加入 verbatim 环境幻灯片就会崩。
beamer 与普通 document class 的不同之处
从写下 \documentclass{beamer} 那一刻起,那些用来推动分页的工具就失效了。把 \newpage 放进 frame 里,既不报错也不警告,只是被忽略——实际试一下,\newpage 两侧的两段会并排出现在同一张幻灯片上。原因很直接:在 beamer 里,决定分页的是 frame 的边界,而不是作者。同理,\section{...} 在正文中什么也不显示,它只是登记进目录和导航。而写在任何 \begin{frame} 之外的文字也不会报错,它会被排成一张没有主题的裸页。「怎么中间多出一张奇怪的页」几乎都源于此。
另一处与纸面文档不同的是尺寸:beamer 排的是屏幕,不是纸张。默认是 4:3,beamer.cls 里写作 \beamer@paperwidth{12.80cm} 与 \beamer@paperheight{9.60cm},也就是 128 mm × 96 mm。用 class 选项可以改变比例:\documentclass[aspectratio=169]{beamer} 得到 160 mm × 90 mm 的 16:9。TeX Live 2024 所带版本单独列出的值有八个:1610、169、149、54、43、32、141、2013。有意思的是它如何处理表外的值:传入不在列表里的数字,beamer 会把高度固定在 9.60 cm,再按数位拆分计算比例。写 aspectratio=21,就真的得到 2:1、宽 19.2 cm 的幻灯片。正文字号照常指定,如 \documentclass[11pt]{beamer},默认是 11pt。
frame 环境:一张幻灯片不等于一页
beamer 的核心是 frame 环境。从 \begin{frame} 到 \end{frame} 是一个逻辑屏幕,里面放列表、图和公式。标题用 \frametitle{...} 添加,或作为环境参数传入:\begin{frame}{Title}。关键在于:一个 frame 不一定是一页。用上下一节的 overlay,同一个 frame 会生成多页 PDF,翻页时看起来就是逐步显示。frame 是逻辑屏幕,PDF 页是它的一帧——beamer 自己的文档就把这两个词分开,前者叫 frame,后者叫 slide。
frame 可以在方括号里接选项。最常用的是内容纵向溢出时的 [allowframebreaks]。加上它之后,beamer 会把 frame 拆成所需的若干页,而且还会在 frame 标题末尾自动补上罗马数字——灌入 22 项的列表,第一页标题是「Long I」,第二页是「Long II」。此外还有对齐纵向位置的 [t](顶部)、[c](居中)、[b](底部),去掉主题装饰好让图占满整屏的 [plain],供 \againframe 之后重新调用的 [label=...],以及不计入 frame 编号的 [noframenumbering]。下一节的 [fragile] 也写在同一位置。
标题元数据与 article 一样在导言区声明。写 \title{...}、\author{...}、\institute{...}、\date{...},然后在正文中把 \titlepage 放进一个 frame,就会排出标题幻灯片(\maketitle 结果相同)。较长的演示里,用 \section{...} 分隔内容后,这些结构会反映到每张幻灯片顶部的导航中。声明好分段之后,把 \tableofcontents 放进一个 frame 就得到目录幻灯片,而 \tableofcontents[currentsection] 会只强调当前所在的节。若想在每节开头自动插入这样的 frame,可在导言区用 \AtBeginSection[]{...} 布置。
Overlay:\pause 与 <2-> 的区别
逐步呈现内容靠的就是 overlay,入口有两个。\pause 只要放在 frame 中间,后面的内容就被送到下一张幻灯片——省事,但只能按源码顺序一步步累加。另一个是 overlay specification,也就是紧跟在命令之后的尖括号 <...>。\item<1-> 表示「从第 1 帧起一直显示」,\item<2> 表示「只在第 2 帧」,\item<2-> 表示「第 2 帧起」。也可以把范围和跳号并列,如 <-2,4-5,7>。实际编译一下,行为与写法完全一致:带 \item<3> 的项目在第 3 帧出现,\only<2>{...} 只在第 2 帧露面,\uncover<3->{...} 从第 3 帧开始可见。
| 命令 | 行为 | 隐藏时的占位 |
|---|---|---|
\pause | 把后续内容送到下一张幻灯片 | 内容依次追加,因此不成问题 |
\uncover<2->{...} | 在指定帧显现 | 始终保留,因此布局不会跳动 |
\onslide<2->{...} | 在指定帧显示,其余隐藏 | 始终保留 |
\only<2>{...} | 只在指定帧输出 | 不保留,后面的内容会往上挤 |
\alert<2>{...} | 在指定帧切换为强调色 | 始终可见,因此始终保留 |
[<+->] | 加在列表环境上,自动逐项推进 | 与 \uncover 相同 |
这张表真正有用的是第三列。\uncover 和 \onslide 即使在隐藏时也保留空间,所以项目出现时周围不会动。\only 则会插入或移除输出本身,隐藏的空间被收回,后面的内容会上下移动。要替换公式的一部分时,\only 正是所需;但若只是顺次展示项目列表,它就是个陷阱,用 \uncover 或 [<+->] 更稳妥。同样的 overlay 语法也适用于 \textbf 和 \textcolor,不只是 \alert,所以「只在这一帧加粗」不需要新的语法。
% the blunt instrument: everything after \pause moves to the next slide
\begin{frame}{Results}
\begin{itemize}
\item First point
\pause
\item Second point
\end{itemize}
\end{frame}
% overlay specifications: say exactly which slides each piece belongs to
\begin{frame}{Results}
\begin{itemize}
\item<1-> Always there
\item<2-> From slide two
\item<3> Slide three only
\end{itemize}
\only<2>{Shown on slide 2, and takes no space otherwise}
\uncover<3->{Space is reserved from the start, ink appears on slide 3}
\end{frame}
% the same stepwise reveal, without numbering each item by hand
\begin{frame}{Results}
\begin{itemize}[<+->]
\item Observation
\item Interpretation
\item Limitation
\end{itemize}
\end{frame}主题:城市、飞禽、花卉与海洋生物
主题共有五类,而且看名字就知道属于哪一类。开头提到的城市名(Madrid、Warsaw、Berlin、Singapore 等)是 presentation theme,也就是一次性决定全局的那种。配色主题的命名更彻底,手册自己就把谜底揭开了:飞禽(albatross、beetle、crane)是自行指定全部颜色的「完整」配色主题;花卉(lily、orchid、rose)是内部配色主题,只改变 block 等内部元素的颜色;海洋生物(whale、dolphin、seahorse)是外部配色主题,管的是页眉、页脚和侧边栏的配色。所以一写下 \usecolortheme{whale},名字就已经告诉你它只动边框周围的东西。
| 命令 | 设置内容 | 示例 |
|---|---|---|
\usetheme | 一次性决定布局、导航和配色 | \usetheme{Madrid}(城市名) |
\usecolortheme | 只替换配色 | \usecolortheme{seahorse}(海洋生物=外部) |
\usefonttheme | 标题与正文的字体 | \usefonttheme{serif}, \usefonttheme{professionalfonts} |
\useinnertheme | 内部元素的样式(列表符号、block 形状) | \useinnertheme{rounded} |
\useoutertheme | 外框样式(页眉、页脚、侧边栏) | \useoutertheme{infolines} |
实务上最快的做法是先选定一个 \usetheme{...},再用它下面的四个命令覆盖不满意的部分。按目的来挑:不想要导航条就用 Madrid 或 Boadilla;想让听众看到当前位置就用 Frankfurt 或 Warsaw。若想要更现代的外观,metropolis(\usetheme{metropolis})是常见答案——它不属于 beamer 本体,但作为独立宏包收录在 TeX Live 中。一句提醒:反复切换主题最容易白白耗掉一个下午。听众看的是内容而不是配色,请尽早定下一个,回到写作上。
block 与 columns:加框强调与左右分栏
要用带框的盒子突出内容,使用 block 环境:\begin{block}{Title}…\end{block} 会生成配色与主题一致、带标题的盒子。提示警告用的 alertblock 和示例用的 exampleblock 写法相同;定理与定义可直接使用 theorem、definition 环境(beamer 会自动载入 amsthm)。要把幻灯片左右分开,就在 columns 环境 里并列 \column{width}——把图和说明并排放置时的常规做法。
\begin{frame}{Comparison}
\begin{columns}
\column{0.5\textwidth}
\begin{block}{Before}
The old estimate.
\end{block}
\column{0.5\textwidth}
\begin{alertblock}{After}
The corrected one.
\end{alertblock}
\end{columns}
\end{frame}为什么加入 verbatim 会让 frame 崩溃,以及 [fragile] 做了什么
把 verbatim 环境或 listings 宏包的 lstlisting(显示源代码)放进 frame 里,只要没写 \begin{frame}[fragile],编译就会停下。麻烦的是它停下的方式。在 TeX Live 2024 上试验,beamer 指向的不是行号而是整个文件,并且说:Runaway argument?,接着 ! File ended while scanning use of \@xverbatim.,然后 I suspect you have forgotten a }, causing me to read past where you wanted me to stop.,最后是 ! Emergency stop.。你会看到一个自己从没敲过的内部宏名,外加一句言之凿凿的诊断:你漏了一个右括号。可根本没有括号没闭合。照这个建议去数括号,只会在一个括号毫无问题的文件里白花很长时间。
真正的原因不是括号,而是读取的顺序。beamer 会先把 frame 的全部内容作为参数整块读入,再按 overlay 的帧数逐次重排。可是 verbatim 的机制是「在读取时改变字符的处理方式」,对已经被吞下去的内容来说为时已晚——错误以 Runaway argument?(参数失控)开头正是因为如此:事故恰恰发生在内容被当作参数读取的过程中。加上 [fragile],beamer 就走另一条路。用用户指南自己的话说,frame 的内容会先写到外部文件,再读回来。实际编译一次就能看见:工作目录里多出一个扩展名为 .vrb 的文件,内容正是该 frame 的正文。
这套「经由外部文件」的机制还带来第二条规则。正如用户指南明确指出的,在带 [fragile] 的 frame 中,\end{frame} 必须单独占一行(前置空白除外)。因为 beamer 是靠「行首的 \end{frame}」这个字符串来判断写出到哪里为止的,所以像 \end{verbatim} \end{frame} 这样挤在一行,同样会失败,这次报出的是另一个内部宏名:! File ended while scanning use of \next.。还有一点:\alert<2>{...} 之类的 overlay 命令在 verbatim 内部无效——原样输出字符正是 verbatim 的本职。若要强调代码的一部分,请改用 beamer 自带的 semiverbatim 环境:它与 verbatim 几乎相同,只是 \、{、} 仍作为命令保留,因此可以插入 \alert<2>{...}。
\begin{frame}[fragile]{An algorithm} % [fragile] -> body goes via a .vrb file
\begin{verbatim}
int main(void) { return 0; }
\end{verbatim}
\end{frame} % must be alone on its own line
% to highlight part of a listing, use semiverbatim rather than verbatim
\begin{frame}[fragile]{Highlighted}
\begin{semiverbatim}
for (int i = 2; i < 100; i++)
\alert<2>{if (is_prime[i])}
\end{semiverbatim}
\end{frame}可编译的最小 beamer 文档
下面是包含主题、标题幻灯片和逐步显示列表的最小配置。导言区声明主题和标题元数据;正文中第一个 frame 放 \titlepage,第二个 frame 放带 [<+->] 的列表。虽然只有两个 frame,但由于 overlay,PDF 会展开成 4 页。若要做日文幻灯片,请在导言区加上与引擎匹配的日文支持,例如在 LuaLaTeX 下载入 luatexja。
\documentclass[aspectratio=169,11pt]{beamer}
\usetheme{Madrid}
\usecolortheme{seahorse}
\title{My Talk}
\author{Ada Lovelace}
\institute{Analytical Engine Lab}
\date{\today}
\begin{document}
\begin{frame}
\titlepage
\end{frame}
\begin{frame}{Overview}
\begin{itemize}[<+->]
\item Background
\item Method
\item Results
\end{itemize}
\end{frame}
\end{document}面向真实演讲的写作流程
beamer 不是把论文切碎的工具。先把演讲流程分成「问题、方法、结果、结论」几段,每个 frame 只放一个主张。不要从正文稿粘贴长段落,而要压缩成图、公式和简短列表,只在逐步呈现真正有用的地方才加 \pause 或 <2->。overlay 是控制讲解顺序的工具,不是装饰。
- 先定下宽高比 — 如果知道投影环境,在动手设计之前就锁定
aspectratio=169或43。之后再改,已经摆好的图会全部错位。 - 每张的密度 — 列表控制在 3 到 5 项。内容溢出时,把 frame 拆开通常比逃向
[allowframebreaks]更好读。 - 代码和日志 — 含
verbatim、lstlisting或minted的 frame 一定要加[fragile],并让\end{frame}单独占一行。 - 要突出图的 frame — 加上
[plain]可去掉主题的边框装饰,让图占满整屏。 - 用于分发的 PDF — 演讲用和分发用是两份不同的文档。用
handout模式折叠 overlay 以及编写讲者备注,请见「讲义」页。