amsthm 宏包提供了定理类和证明类环境,但是它们并不是开箱即用的,这里记录一下相关的使用方式和配置。

定理类环境

基于 amsthm 包可以创造定理类环境,语法包括如下几类

1
2
3
4
5
6
\newtheorem{name}{text}                     % 独自使用计数器
\newtheorem{name}{text}[section-level] % 基于section层级设置计数器
\newtheorem{name}{text}[counter] % 基于计数器层级设置下一层的计数器
\newtheorem{name}[counter]{text} % 共享其它环境的计数器

\newtheorem*{name}{text} % 不使用计数器

其中

  • name:必选的定理类环境的标识符(名称)
  • text:必选的显示环境名称(引导词)
  • 可选项的位置和名称有不同含义:
    • counter 在前面:共享前者的计数器,例如前者为1.1,后者则为1.2;
    • counter 在后面:继承前者的计数器,例如前者为1.1,后者则为1.1.1;
    • section-level 在后面:编号计数器依赖于某个章节层次,例如section 1的编号从1.1开始。

下面的常用环境都可以基于定理环境创建:(按照字体风格进行了分类)

  • plain 风格
    • 定理 theorem
    • 推论 corollary
    • 引理 lemma
    • 命题 proposition
  • definition 风格
    • 定义 definition
    • 例子 example
    • 问题 problem
  • remark 风格
    • 注记 remark(remark*)
    • 笔记 note(note*)

使用时例如

1
2
3
\begin{theorem}
...
\end{theorem}

或者可以加上额外名称,会在引导词后加上括号显示

1
2
3
\begin{theorem}[xxx]
...
\end{theorem}

关于下面三个写法有必要辨析一下

1
2
3
\newtheorem{theorem}{Theorem}[section]
\newtheorem{corollary}{Corollary}[theorem]
\newtheorem{lemma}[theorem]{Lemma}

三者的区别为:

  • 对于theorem,根据当前section创建子编号;
  • 对于corollary,根据最近一次的theorem创建子编号,例如theorem 1.1之后的corollary采用编号1.1.1;
  • 对于lemma,与theorem共享计数器,例如theorem 1.1之后的lemma则采用编号1.2。

可以使用 \theoremstyle{style} 命令修改定理环境的样式,内置样式有三种:

  • plain(默认样式):引导词是正体,内容是斜体,通常用于定理/推论/引理/命题等
  • definition:引导词和内容都是正体,通常用于定义/条件/示例/问题等
  • remark:引导词是斜体,内容是正体,通常用于remark/note/断言/结论等

注意只有remark的引导词不会加粗显示。

完整的定义语法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[section] % 定理,基于section计数器
\newtheorem{corollary}{Corollary}[theorem] % 推论,继承定理的计数器(定理1.1,推论1.1.1)
\newtheorem{lemma}[theorem]{Lemma} % 引理,共享定理的计数器
\newtheorem{proposition}[theorem]{Proposition} % 命题,共享定理的计数器

\theoremstyle{definition}
\newtheorem{definition}{Definition}[section] % 定义,基于section计数器
\newtheorem{example}{Example}[section] % 示例,基于section计数器
\newtheorem{problem}{Problem}[section] % 问题,基于section计数器

\theoremstyle{remark}
\newtheorem{remark}{Remark}[section] % remark,基于section计数器
\newtheorem*{remark*}{Remark} % remark*,无编号
\newtheorem{note}{Note}[section] % note,基于section计数器
\newtheorem*{note*}{Note} % note*,无编号

这里习惯使用 ABC* 表示与 ABC 相同语义,但是不带编号的环境。

我们还可以使用thmtools宏包更简单直观地实现上述定理的设置,与上面几乎等价的一组配置命令如下 (与上文不完全相等,这里进行了简化,直接将推论和命题等视作一类,共享定理的计数器)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
\usepackage{thmtools}

\declaretheorem[style=plain, numbered=yes, name=Theorem, numberwithin=section]{theorem}
\declaretheorem[style=plain, name=Corollary, sibling=theorem]{corollary}
\declaretheorem[style=plain, name=Lemma, sibling=theorem]{lemma}
\declaretheorem[style=plain, name=Proposition, sibling=theorem]{proposition}

\declaretheorem[style=definition, numbered=yes, name=Definition, numberwithin=section]{definition}
\declaretheorem[style=definition, name=Example, numberwithin=section]{example}
\declaretheorem[style=definition, name=Problem, numberwithin=section]{problem}

\declaretheorem[style=remark, numbered=yes, name=Remark, numberwithin=section]{remark}
\declaretheorem[style=remark, name=Remark, numbered=no]{remark*}
\declaretheorem[style=remark, name=Note, numberwithin=section]{note}
\declaretheorem[style=remark, name=Note, numbered=no]{note*}

补充:在定理类环境中如何直接使用列表环境,会导致第一项直接在首行的名称之后出现,与列表后续项的缩进不一致,看着很奇怪,可以通过在第一项之前加上\noindent实现。

证明类环境

amsthm也提供了用于写证明/解答的proof环境,不含有编号,默认样式包括:引导词Proof为斜体,内容是正体,结尾会自动添加证毕的方框符号。 可以直接使用,并不需要手动定义

1
2
3
\begin{proof}
...
\end{proof}

在默认情况下,proof环境使用斜体的proof作为默认引导词。

通过修改\proofname可以替换默认引导词,例如可以将默认引导词改为加粗的正体 proof

1
\renewcommand*{\proofname}{\normalfont\bfseries Proof}

由于ctex默认会将\proofname修改为中文的证明,这里改回来

1
\renewcommand{\proofname}{\normalfont\bfseries Proof}

proof环境支持可选参数,可选参数会替换默认的引导词,例如

1
2
3
\begin{proof}[\normalfont\bfseries Solution]
...
\end{proof}

可以用来强调是某个定理/命题的证明,尤其在定理和证明分离时,例如

1
2
3
\begin{proof}[\normalfont\bfseries Proof of Theorem~\ref{thm:1}]
...
\end{proof}

可以简单地通过修改默认引导词定义一个与证明环境类似的解答环境。

1
\newenvironment{solution}{\begin{proof}[\textbf{Solution}]}{\end{proof}}

对于以不带编号公式结尾的证明,默认情况下证毕符号会另起一行,不太美观,可以使用\qedhere命令将证毕符号放在公式行的末尾,例如

1
2
3
4
5
6
\begin{proof}
For simplicity, we use
\[
E=mc^2 \qedhere
\]
\end{proof}

对于带编号的公式,则不建议使用\qedhere命令,因为编号和证毕符号的排版可能异常,不够美观。 对于多行公式最好也不要使用,因为证毕符号出现的位置可能不符合期望。

注:这里并没有对证明的引导词 Proof 采用缩进,可以加入\indent实现。

习题与解答环境

习题与解答环境也是一个常见的需求,下面提供一种直接基于 framed 宏包的简易实现,对于习题环境会加上背景色,习题环境不含编号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
\documentclass{ctexart}
\usepackage{xcolor,framed}
\definecolor{shadecolor}{RGB}{241, 241, 255} % 背景色

\newenvironment{problem}{\begin{shaded}\noindent\textbf{题目: }}{\end{shaded}}
\newenvironment{solution}{\par\noindent\textbf{解答: }}{\par}

\begin{document}

\begin{problem}
$x^2 - 5x + 6 = 0$,求其根。
\end{problem}

\begin{solution}
由因式分解得 $x=2$$x=3$
\end{solution}

\end{document}

tcolorbox 宏包基础

LaTeX 的 tcolorbox 宏包是最常见的盒子样式美化宏包,在各个模板中都广泛使用,tcolorbox 宏包的功能非常复杂丰富,文档长达五百多页,还可以深度结合 tikz 得到更丰富的样式。下面简单记录一下 tcolorbox 最基础的一些用法,这里使用 lipsum 宏包生成对应的填充文本。

tcolorbox 宏包的功能模块化,可以按需进行导入,为了使用方便,可以直接加上 [most] 选项

1
\usepackage[most]{tcolorbox}

首先从 tcolorbox 环境开始,用法如下

1
2
3
\begin{tcolorbox}[<options>]
\lipsum[1][1-3]
\end{tcolorbox}

可以通过可选参数来设置盒子的样式,最基础的选项包括:

  • colback: 背景色
  • colframe: 边框色
  • title:盒子标题

注意:

  • 不设置任何选项则会使用默认样式;
  • 如果出现重复选项,不会报错,后者会对前者进行覆盖。

例如

1
2
3
4
5
6
7
\begin{tcolorbox}
\lipsum[1][1-3]
\end{tcolorbox}

\begin{tcolorbox}[colback=red!5!white,colframe=red!75!black,title={My title}]
\lipsum[2][1-3]
\end{tcolorbox}

可以通过 \tcbset 命令设置 tcolorbox 的默认样式,对后续的所有盒子生效,例如

1
\tcbset{colback=red!5!white,colframe=red!75!black}

还可以在 \tcbset 命令中定义预设样式,然后就可以在样式选项中用 myboxstyle 替代,例如

1
2
3
4
5
6
7
8
9
\tcbset{
myboxstyle/.style={
colback=yellow!20!white,
colframe=yellow!70!black}
}

\begin{tcolorbox}[myboxstyle]
\lipsum[3][1-3]
\end{tcolorbox}

这三个盒子的效果如下图(第一个是默认样式)

除了直接使用 tcolorbox 环境,还可以使用 \newtcolorbox 命令生成新的 tcolorbox 环境,作用相当于 \newenvironment 命令。

1
\newtcolorbox[<init options>]{<name>}[<number>][<default>]{<options>}

例如一个不含参数的新环境

1
2
3
4
5
\newtcolorbox{mybox1}{colback=red!5!white,colframe=red!75!black}

\begin{mybox1}
\lipsum[1][1-3]
\end{mybox1}

一个带必选 title 参数的新环境

1
2
3
4
5
6
7
\newtcolorbox{mybox2}[1]{colback=red!5!white,
colframe=red!75!black,fonttitle=\bfseries,
title={#1}}

\begin{mybox2}{My Box Title}
\lipsum[2][1-3]
\end{mybox2}

一个带可选 title 参数的新环境

1
2
3
4
5
6
7
8
9
10
11
\newtcolorbox{mybox3}[1][]{colback=red!5!white,
colframe=red!75!black,fonttitle=\bfseries,
title={Note\ifx\relax#1\relax\else: #1\fi}}

\begin{mybox3}[My Box Title]
\lipsum[3][1-3]
\end{mybox3}

\begin{mybox3} % no title
\lipsum[4][1-3]
\end{mybox3}

这四个盒子的效果如下图

可以将新环境接收的选项继续传递给 tcolorbox,达到允许临时修改样式的目的,例如

1
2
3
4
5
6
7
8
9
\newtcolorbox{cbox}[1][]{%
enhanced,
breakable,
sharp corners,
leftrule=2pt, rightrule=0pt, toprule=0pt, bottomrule=0pt,
colframe=SkyBlue,
colback=SkyBlue!8,
#1
}

可以在 \newtcolorbox 命令的 init options 设置编号规则,在 options 中通过 \thetcbcounter 获取编号,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
\section{Demo}

\newtcolorbox[auto counter,number within=section]{cntbox}[1][]{colback=red!5!white,
colframe=red!75!black,fonttitle=\bfseries,
title={Note~\thetcbcounter\ifx\relax#1\relax\else: #1\fi}}

\begin{cntbox}[My Box Title]
\lipsum[1][1-3]
\end{cntbox}

\begin{cntbox}
\lipsum[2][1-3]
\end{cntbox}

除了 \newtcolorbox 命令,还可以使用 \renewtcolorbox 命令重新定义现有环境。

下面考虑一些更复杂的样式,相关选项的解释如下:

  • enhanced:支持更复杂的样式(否则部分样式选项无效),但是会降低编译效率
  • breakable:支持分页
  • fonttitle:标题字体
  • frame hidden:隐藏边框
  • boxrule=1pt:边框宽度
  • leftrule=2pt, rightrule=0pt, toprule=0pt, bottomrule=0pt:分别指定每一个方向的边框宽度
  • rounded corners / sharp corners:圆角 / 直角边框(默认圆角)
  • drop shadow={black!50!white}:生成盒子阴影

对应源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
\begin{tcolorbox}[
enhanced,
breakable,
sharp corners,
leftrule=2pt, rightrule=0pt, toprule=0pt, bottomrule=0pt,
colframe=SkyBlue,
colback=SkyBlue!8]
\lipsum[1][1-3]
\end{tcolorbox}

\vspace{0.5cm}

\begin{tcolorbox}[
enhanced,
breakable,
colback=orange!2,
frame hidden,
overlay={
\draw[orange!75, line width=2pt]
(frame.north west) -- ++(3mm,0)
(frame.north west) -- ++(0,-3mm)
(frame.south east) -- ++(-3mm,0)
(frame.south east) -- ++(0,3mm);
}]
\lipsum[2][1-3]
\end{tcolorbox}

\vspace{0.5cm}

\begin{tcolorbox}[
enhanced,
breakable,
colframe=SkyBlue,
colback=SkyBlue!8,
title={Note},
fonttitle=\bfseries,
attach boxed title to top left={xshift=4mm,yshift=-2mm},
boxed title style={size=small,colback=SkyBlue!80!black}]
\lipsum[3][1-3]
\end{tcolorbox}

\vspace{0.5cm}

\begin{tcolorbox}[
enhanced,
breakable,
sharp corners,
colback=yellow!20!white,
colframe=yellow!70!black,
drop shadow={black!50!white},
title={Note},
fonttitle=\bfseries\color{black},
attach boxed title to top left={xshift=-2mm,yshift=-2mm},
boxed title style={size=small,colback=yellow!80!black,colframe=yellow!70!black}]
\lipsum[4][1-3]
\end{tcolorbox}

通过\newtcolorbox 命令将这些样式封装为新环境也是容易的。

例如基于第一个样式,定义一个可以接收参数以调整盒子样式的新环境 cbox

1
2
3
4
5
6
7
8
9
\newtcolorbox{cbox}[1][]{%
enhanced,
breakable,
sharp corners,
leftrule=2pt, rightrule=0pt, toprule=0pt, bottomrule=0pt,
colframe=SkyBlue,
colback=SkyBlue!8,
#1
}

例如基于第二个样式,定义一个适合引用原文的新环境 cboxquote

1
2
3
4
5
6
7
8
9
10
11
12
13
\newtcolorbox{cboxquote}{
colback=orange!2,
enhanced,
breakable,
frame hidden,
overlay={
\draw[orange!75, line width=2pt]
(frame.north west) -- ++(3mm,0)
(frame.north west) -- ++(0,-3mm)
(frame.south east) -- ++(-3mm,0)
(frame.south east) -- ++(0,3mm);
}
}

例如基于第三个样式,定义一个支持可选标题的新环境 tbox

1
2
3
4
5
6
7
8
9
10
\newtcolorbox{tbox}[1][]{
enhanced,
breakable,
colframe=SkyBlue,
colback=SkyBlue!8,
title={#1},
fonttitle=\bfseries,
attach boxed title to top left={xshift=4mm,yshift=-2mm},
boxed title style={size=small,colback=SkyBlue!80!black},
}

例如基于第四个样式,定义支持可选标题的便利贴样式的新环境 notebox/notebox*,分别带编号和不带编号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
\tcbset{
noteboxstyle/.style={
enhanced,
breakable,
sharp corners,
colback=yellow!20!white,
colframe=yellow!70!black,
drop shadow={black!50!white},
fonttitle=\bfseries\color{black},
attach boxed title to top left={xshift=-2mm,yshift=-2mm},
boxed title style={size=small,colback=yellow!80!black,colframe=yellow!70!black}}
}

\newtcolorbox[auto counter, number within=section]{notebox}[1][]{
noteboxstyle, title={Note~\thetcbcounter\ifx\relax#1\relax\else: #1\fi}
}
\newtcolorbox{notebox*}[1][]{
noteboxstyle, title={Note\ifx\relax#1\relax\else: #1\fi}
}

通过 \tcolorboxenvironment 命令可以用 tcolorbox 环境封装已有的环境,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
\declaretheorem[style=plain, name=Theorem, numbered=yes, numberwithin=section]{theorem}
\declaretheorem[style=plain, name=Theorem, numbered=no]{theorem*}

\tcolorboxenvironment{theorem}{
enhanced,
breakable,
sharp corners,
leftrule=2pt, rightrule=0pt, toprule=0pt, bottomrule=0pt,
colframe=RoyalPurple,
colback=RoyalPurple!8
}
\tcolorboxenvironment{theorem*}{
enhanced,
breakable,
rounded corners,
leftrule=2pt, rightrule=0pt, toprule=0pt, bottomrule=0pt,
colframe=RoyalPurple,
colback=RoyalPurple!8
}