1994 年 6 月 1 日,LaTeX 把一条命令拆成了两条;从那以后,每一份 LaTeX 文档都以同样的方式开头:一行 \documentclass,接着是由 \usepackage 组成的 导言区。在此之前人们写的是 \documentstyle[12pt,twoside]{article},把选项和附加样式一起塞进同一对方括号里。把 文档类 和宏包分开,并不是为了整齐。类决定 文档是什么——论文、报告、书籍,还是一叠幻灯片;导言区决定 文档能做什么。这条界线划对了,期刊改一行就能把整份稿件重新排版;划错了,本该用来写作的一个晚上就耗在 Option clash for package geometry 上。
\documentclass 到底决定了什么
\documentclass[options]{class} 是文档中必须写在 最前面 的唯一命令;在它之前只允许出现以 % 开头的注释。花括号里是类名,方括号里是选项——而花括号中的名字指向磁盘上一个真实存在的文件。写 article,加载的就是 article.cls,那是几百行定义,里面装的全是规则。例如 \section 标题用 \Large\bfseries 排,上方留 3.5ex,下方留 2.3ex——这三个数值就明明白白写在 article.cls 里。而你的正文,一个字也不在其中。
这种分工并非偶然。1980 年代初,莱斯利·兰波特正着手写一本书,发现当时流行的宏包不够用;他既然要为这本书写一套宏,就顺势想到:再多花一点力气,这套宏也能给别人用。在 2000 年 1 月《DMV-Mitteilungen》的访谈中,他把这称作 LaTeX 的起点。所以,类就是把 结构与外观的分离 直接做成了一个文件。正文里只写 \section{Introduction},也就是只写语义;把它排成加大加粗、编上号、上方留空,是类的事。学会和出版社自己发布类,原因正在于此——amsart、IEEEtran、elsarticle、revtex4-2、acmart 都真实存在,而且常被投稿须知指定。兰波特本人在 1980 年代后期就向 ACM 提过这个想法:为 TeX/LaTeX、troff 和 Scribe 各做一套标准文档样式,好让电子投稿走得更快——只是被一位 ACM 编辑回绝了。
% Only the first line changes; the body stays as it is.
\documentclass[11pt,a4paper]{article} % top level heading is \section
% \documentclass[11pt,a4paper]{book} % \chapter becomes available
\begin{document}
\section{Introduction}
The source carries the structure; the class supplies the appearance.
\end{document}article、report、book 到底差在哪里
实际差别归结为两点:有没有章,以及 是否默认双面。article.cls 根本没有定义 \chapter,所以最上层是 \section;report.cls 和 book.cls 都定义了。默认值就写在各自类文件的 \ExecuteOptions 那一行:article 是 letterpaper,10pt,oneside,onecolumn,final,report 在此基础上加 openany,只有 book 换成 twoside 和 openright。最容易踩坑的是纸张——三者的默认都是 letterpaper,想要 A4 就得自己写 a4paper。标题的处理也不同:article 的标题接在正文第一页顶部,report 和 book 则单独占一页。
| 类 | 适合的文档 | 章与默认值 |
|---|---|---|
article | 论文、笔记、通用的中短篇文档 | 无 \chapter;oneside、onecolumn、notitlepage |
report | 技术报告、学位论文、分章的长文 | 有 \chapter;oneside、openany,独立标题页 |
book | 成书 | 有 \chapter;twoside、openright,章从右页开始 |
letter | 信函 | 无分节命令;\address、\signature、\opening、\closing |
book 还有一层机制值得知道:\frontmatter / \mainmatter / \backmatter,它们各用大约一行代码实现了纸书的惯例。\frontmatter 调用 \pagenumbering{roman},让序言和目录用小写罗马数字(i, ii, iii…),并停掉章编号。\mainmatter 调用 \pagenumbering{arabic},把页码从 1 重新数起,并恢复章编号。\backmatter 保留阿拉伯页码但再次去掉章编号,于是索引不会变成「第 12 章 索引」。凡是序言编作 i, ii, iii 而正文又从 1 重新开始的书,都是这三行的结果。
标准的四个不够用时,CTAN 上几乎有面向各种用途的类。做报告首选 beamer:一个 frame 环境就是一张幻灯片,逐步显示(overlay)和主题都是现成的。若觉得标准类的默认排版偏旧,KOMA-Script 的 scrartcl / scrreprt / scrbook 分别对应 article / report / book,且提供了丰富得多的细节调整接口。日文排版方面:pLaTeX / upLaTeX 用奥村晴彦与 texjporg 维护的 jsarticle / jsbook(jsclasses),LuaLaTeX 用其 LuaTeX-ja 版本 ltjsarticle / ltjsbook,此外还有基于《日本语组版处理要求》(JLReq)的 jlreq,它会自动判别引擎,并通过 report、book 选项切换为 report 或 book 的行为。无论哪种情况,第一个要问的都是同一句话:类和你实际使用的引擎对得上吗?
\documentclass 的选项都是什么意思
选项是写在方括号里、以逗号分隔、作用于整篇文档的开关,例如 \documentclass[11pt,a4paper,twoside]{article}。顺序无关紧要;如果给出同一族的两个选项(比如 oneside 和 twoside),后写的生效。下表列出的是实际会用到的选项,但真正值得记住的是默认值:正文 10pt、纸张 letterpaper、版面 onecolumn。如果打算按 A4 打印,a4paper 每次都得自己写上。
| 选项 | 效果 | 默认 |
|---|---|---|
10pt / 11pt / 12pt | 正文基准字号;标题和脚注按比例随之变化 | 10pt |
a4paper / letterpaper | 纸张尺寸;另有 a5paper、b5paper、legalpaper、executivepaper | letterpaper |
twocolumn / onecolumn | 把正文排成双栏;浮动体的放置也要改用 figure* 之类 | onecolumn |
twoside / oneside | 让左右页的边距与页眉不对称,便于装订 | oneside;book 为 twoside |
openright / openany | 章是否必须从奇数(右)页开始 | book 为 openright,report 为 openany |
titlepage / notitlepage | \maketitle 是否独占一页 | report、book 为 titlepage,article 为 notitlepage |
fleqn / leqno | 行间公式左对齐 / 公式编号放在左侧 | 居中,编号在右 |
draft / final | 用页边的黑条标出溢出的行(overfull box) | final |
这里有一个机制,不知道就一定会踩一次:写在 \documentclass 里的选项并不只属于类,它们会作为 全局选项 交给此后加载的每一个宏包。按 clsguide 的说法,直接写在 \usepackage[...] 里的是局部选项,写在 \documentclass[...] 里的是全局选项,而宏包会从两边挑出自己认识的选项名。所以写 \documentclass[twocolumn]{article},凡是懂双栏的宏包都会悄悄按双栏行事。同一机制也是 ! LaTeX Error: Option clash for package geometry. 的解药:当同一个宏包被带着不同选项加载两次时(多半是类或模板已经加载过一次),就会出现这一行。LaTeX 自己在日志里给的建议就是把那个选项挪到 \documentclass 声明中去,因为全局选项不会与第二次加载相冲突。
什么写进导言区,什么写进正文
导言区从 \documentclass 的下一行起,到 \begin{document} 之前为止,其中只能放 声明,不能有正文的任何一个字。在这里写下一句普通的话,编译就会停在 ! LaTeX Error: Missing \begin{document}.。这个名字有点误导,它的真正含义是「正文还没开始,就来了要排版的字符」。导言区里 % 注释没写完,或混进了全角空格之类的字符,也会看到同样这一行。反过来,在正文里调用 \usepackage,得到的是 ! LaTeX Error: Can be used only in preamble.——所有宏包都必须在开始排第一页之前到齐。
- 加载宏包 —
\usepackage[options]{package}。可以写成\usepackage{amsmath,amssymb}合并加载,但这种写法无法附带选项。 - 标题信息 —
\title{...}、\author{...}、\date{...}。真正排出标题的是正文中的\maketitle;按惯例这三条声明放在导言区。 - 自定义命令与环境 —
\newcommand、\renewcommand、\newenvironment,用于贯穿全文的结构。 - 长度与计数器 —
\setlength{\parindent}{0pt}、\setcounter{tocdepth}{2}等作用于全文的数值。 - 页面样式与宏包配置 —
\pagestyle{headings}、\hypersetup{...}、\graphicspath{{figures/}}这类加载之后的调整。 - 绝不能放的东西 — 标题、段落、插图、表格;凡是会出现在输出里的,都属于
\begin{document}之后。
宏包应该按什么顺序加载
大多数宏包并不在意顺序,但那几个例外值得记牢。最有名的是 hyperref,其手册明确写着:它应当排在所加载宏包的 最后。理由很直白——hyperref 的工作就是重定义大量 LaTeX 命令;过早加载,后来的宏包就会覆盖这些重定义,于是链接和 PDF 书签会悄无声息地失效。手册在这条建议后还加了脚注,说明已经开始着手减少重定义的数量、从而削弱对加载顺序的依赖。也就是说,这是眼下的权宜之计,而非永恒定律。
而这个「最后」有一个著名的例外:cleveref 必须在 hyperref 之后加载。 cleveref 要先检测 hyperref 定义了什么,再据此构建自己的引用命令,顺序反过来就不管用。如果同时用 varioref,其手册规定的顺序是 varioref → hyperref → cleveref。这个坑的可恨之处在于它失败得悄无声息——cleveref 手册明确警告:顺序错了,交叉引用会指向完全不相干的对象,而且 输出和日志里都不会有任何警告。要是曾遇到引用编号莫名其妙差一位,先去看导言区里这三行的顺序。
\documentclass[11pt,a4paper]{article}
% 1. encoding and fonts
\usepackage[T1]{fontenc}
% 2. language
\usepackage[english]{babel}
% 3. page geometry
\usepackage[margin=25mm]{geometry}
% 4. mathematics
\usepackage{amsmath,amssymb}
% 5. graphics and colour
\usepackage{graphicx}
\usepackage{xcolor}
% 6. hyperref near the end: it redefines many commands
\usepackage{hyperref}
% 7. cleveref is the exception, it must come after hyperref
\usepackage{cleveref}
% document-wide settings and definitions
\newcommand{\R}{\mathbb{R}}
\setlength{\parindent}{0pt}
\title{A Short Note}
\author{Ada Lovelace}
\date{\today}
\begin{document}
\maketitle
\section{Setup}\label{sec:setup}
For all $x \in \R$ we have $x^2 \ge 0$.
\section{Result}
The argument of \cref{sec:setup} applies unchanged.
\end{document}别让导言区长得比正文还大
还是在那次访谈里,兰波特被问到「用户应当停止犯的三个 LaTeX 错误是什么」。他给出的三个答案是同一句:太在意排版,太不在意内容。重复三遍本身就是答案。导言区正是这个陷阱的所在地——只用一次的外观微调、试过就忘了删的宏包、只写过两次的缩写命令,一点点堆起来。代价不是难看,而是日后真出错时,元凶就藏在那几十行里的某处。只保留 作用于全文 的东西:类、语言与字体、数学、图表、链接。\newcommand 只留给写作过程中确实反复出现的结构。若用的是投稿模板,先尊重模板的导言区——擅自替换类所依赖的宏包,通常会以 Option clash 的形式回来,或者以更难读懂的形式回来。
- 新报告 — 从
article开始。等正文大致写完,再去动版面设计也来得及。 - 学位论文 — 原样使用学校发布的类,边距和标题的调整留到最后;不碰模板导言区往往是最短的路。
- 投稿论文 — 先放上出版方的类(
elsarticle、IEEEtran、revtex4-2等),再在其上补最少量属于自己的导言区。 - 要按 A4 打印 — 标准类的默认是
letterpaper,所以要写明\documentclass[a4paper]{...};若加载了geometry,也可以在那里设定。 - 出现错误时 — 先怀疑最后加进去的
\usepackage或\newcommand;仍找不出,就把导言区砍成一半做二分查找。