LaTeX 新手往往会因系统提供的视觉自定义选项不足而感到失望。实际上,这是故意为之:LaTeX 的哲学是专注于排版,而作者则专注于内容的创作。

在本章中,我们将展示通过一些努力可以实现的效果。

引言

接下来,我们将编写一个主题,这是一个仅改变文档外观的包,确保我们的文档在有或没有主题的情况下都能正常工作。

请注意,尽管这个主题看起来可能很吸引眼球,但这绝对不是一个排版模型。你不应该在严肃的出版物中使用这样的主题。这个例子更像是一个技术展示,用于展示 LaTeX 的能力。

自定义主题(目录)

自定义主题

自定义主题(红色)

包配置

这里没有太多要说的。这是《创建包》章节的直接应用。

我们加载所需的包。

  • needspace 用于防止在章节命令后出现页面换行。

  • tikz 用于绘制精美的内容。

我们定义了一个颜色选项,你可以根据需要使用任意多个选项。使用特定名称定义颜色使得配置更加灵活。我们还使用了一个选项来切换炫酷的反射效果,这个效果可能有点过于炫目!

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{theme-fancy}[2013/01/13 v1.0 fancy theme]

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Packages

\RequirePackage{geometry}
\RequirePackage{needspace}
\RequirePackage[svgnames]{xcolor}

\RequirePackage{hyperref}
\hypersetup{colorlinks=true}

\RequirePackage{fancyhdr}

\RequirePackage{tikz}
\usetikzlibrary{
  calc,
  decorations.pathmorphing,
  fadings,
  shadows,
  shapes.geometric,
  shapes.misc,
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Options

%% Toggle reflection.
\newif\if@mirrors\@mirrorsfalse
\DeclareOption{mirrors}{
  \@mirrorstrue
}

%% Colors.
\newif\if@red\@redfalse
\DeclareOption{red}{
  \@redtrue
}

\ExecuteOptions{}
\ProcessOptions\relax

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Configuration

\renewcommand{\familydefault}{\sfdefault}
\setlength{\parskip}{0.5\baselineskip}

%% Colors
\colorlet{toctitle}{DarkGray!50!black}
\colorlet{titlebg}{MidnightBlue}
\colorlet{titlefg}{LightBlue}
\colorlet{titletxt}{MidnightBlue}
\colorlet{sectionfg}{MidnightBlue}
\colorlet{subsectionfg}{SteelBlue}
\colorlet{subsubsectionfg}{LightSteelBlue!60!black}

\if@red
\colorlet{toctitle}{DarkGray!50!black}
\colorlet{titlebg}{DarkRed}
\colorlet{titlefg}{FireBrick!50}
\colorlet{titletxt}{DarkRed}
\colorlet{sectionfg}{DarkRed}
\colorlet{subsectionfg}{Crimson!50!black}
\colorlet{subsubsectionfg}{LightSteelBlue!60!black}
\fi

页眉和页脚

我们使用 TikZ 来绘制一个填充的半圆形。

fancyhdr 用于设置页眉和页脚。我们使用 fancy 样式,并通过 \fancyhf{} 清空之前的页眉和页脚。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 页眉和页脚

\tikzstyle{foliostyle}=[fill=Lavender, text=MidnightBlue, inner sep=5pt, semicircle]

\pagestyle{fancy}
\fancyhf{}
\fancyfoot[C]{
  \vskip 3pt
  \begin{tikzpicture}
    \node[foliostyle]
    {\bfseries\thepage};
  \end{tikzpicture}
}

\renewcommand{\headrulewidth}{0.8pt}
\addtolength{\headheight}{\baselineskip} 
\renewcommand{\headrule}{\color{LightGray}\hrule}
\fancyhead[LE]{ \textcolor{gray}{\slshape \rightmark} } 
\fancyhead[RO]{ \textcolor{gray}{\slshape \leftmark} }

目录

我们重新定义了 \tableofcontents 使用的命令。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 目录

\newcommand{\sectiontoccolor}{sectionfg}
\newcommand{\subsectiontoccolor}{subsectionfg}
\newcommand{\subsubsectiontoccolor}{subsubsectionfg}

\renewcommand*\l@section{\color{\sectiontoccolor}\def\@linkcolor{\sectiontoccolor}\@dottedtocline{1}{1.5em}{2.3em}}
\renewcommand*\l@subsection{\color{\subsectiontoccolor}\def\@linkcolor{\subsectiontoccolor}\@dottedtocline{1}{2.3em}{3.1em}}
\renewcommand*\l@subsubsection{\color{\subsubsectiontoccolor}\def\@linkcolor{\subsubsectiontoccolor}\@dottedtocline{1}{3.1em}{3.9em}}
\def\contentsline#1#2#3#4{%
  \ifx\\#4\\%
  \csname l@#1\endcsname{#2}{#3}%
  \else
  \csname l@#1\endcsname{\hyper@linkstart{link}{#4}{#2}\hyper@linkend}{%
    \hyper@linkstart{link}{#4}{#3}\hyper@linkend
  }%
  \fi
}

%% 新标题格式 - 默认使用 'section'
\newcommand{\tocformat}[1]{{\Huge\bf#1}}

\renewcommand\tableofcontents{%
  \tocformat{
    \textcolor{toctitle}{\contentsname}
    \@mkboth{\MakeUppercase\contentsname}{\MakeUppercase\contentsname}
  }%
  \@starttoc{toc}%
}

分节

这是最复杂的部分。由于代码几乎相同,sectionsubsectionsubsubsection 处理方式并不复杂。

我们使用 \needspace 来确保章节命令后没有换行。我们将命令包裹在一个组内,并设置字体大小,因为我们需要的空间是 \baselineskip,它取决于字体大小。

对于星号命令,它不会设置计数器(这是 LaTeX 默认行为)。你可以选择通过重置计数器来处理星号命令。

我们在章节打印前加上 \noindent。我们确保通过 \par 命令结束章节打印,以确保后续文本正确打印。

对于 subsection,我们利用 mirrors 选项来相应地改变外观。

为了正确处理 PDF 书签,我们需要在定义结束时添加以下行:

\phantomsection
\addcontentsline{toc}{section}{\thesection~#1}

最终,对于 \section,我们希望它在页眉中打印,因此调用 \sectionmark 命令。这里我们改变了星号命令的行为,与原始 LaTeX 版本不同,因为我们定义并使用了 \sectionmarkstar 命令。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 节样式

\renewcommand\section{
  \@ifstar
  \my@sectionstar
  \my@section
}

%% 注意:为了对齐,文本宽度必须设置为 \textwidth - 2*(inner sep)。
\tikzstyle{sectionstyle}=[
  inner sep=5pt,
  text width=\textwidth-10pt,
  left color=sectionfg!100!white,
  right color=sectionfg!50!white,
  rounded corners,
  text=Ivory,
  rectangle
]

\newcommand\my@section[1]{
  \stepcounter{section}
  {\Large\needspace{\baselineskip}}
  \noindent
  \begin{tikzpicture}
    \node[sectionstyle] {\bfseries\Large\thesection\quad#1};
  \end{tikzpicture}
  \par
  \phantomsection
  \addcontentsline{toc}{section}{\thesection~#1}
  \sectionmark{#1}
}

\newcommand{\sectionmarkstar}[1]{\markboth{\MakeUppercase{#1}}{}}

\newcommand\my@sectionstar[1]{
  {\Large\needspace{\baselineskip}}
  \noindent
  \begin{tikzpicture}
    \node[sectionstyle] {\bfseries\Large#1};
  \end{tikzpicture}
  \par
  \phantomsection
  \addcontentsline{toc}{section}{#1}
  \sectionmarkstar{#1}
}

子节样式

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 子节样式

\renewcommand\subsection{
  \@ifstar
  \my@subsectionstar
  \my@subsection
}

\tikzstyle{subsectionstyle}=[
  left color=subsectionfg!50!white,
  right color=subsectionfg!100!white,
  text=Ivory,
  ellipse,
  inner sep=5pt
]

\newcommand\my@subsection[1]{
  \stepcounter{subsection}
  {\Large\needspace{\baselineskip}}
  \noindent  
  \begin{tikzpicture}
    \node[subsectionstyle,anchor=west] (number) at (0,0) {\bfseries\Large\thesubsection};
    \if@mirrors
    \node[above right,subsectionfg,anchor=south west] at ($(number.east)+(0.1,-0.1)$) {\large\bfseries#1};
    \node[yscale=-1, scope fading=south, opacity=0.4, above, anchor=south west, subsectionfg] at ($(number.east)+(0.1,0.1)$) {\large\bfseries#1};
    \else
    \node[above right,subsectionfg,anchor=west] at ($(number.east)+(0.1,0)$) {\large\bfseries#1};
    \fi
  \end{tikzpicture}
  \par
  \phantomsection
  \addcontentsline{toc}{subsection}{\thesubsection~#1}
}

\newcommand\my@subsectionstar[1]{
  {\Large\needspace{\baselineskip}}
  \noindent
  \begin{tikzpicture}
    \node[subsectionstyle,anchor=west] (number) at (0,0) {\bfseries\Large\phantom{1}};
    % 
    \if@mirrors
    \node[above right,subsectionfg,anchor=south west] at ($(number.east)+(0.1,-0.1)$) {\large\bfseries#1};
    \node[yscale=-1, scope fading=south, opacity=0.4, above, anchor=south west, subsectionfg] at ($(number.east)+(0.1,0.1)$) {\large\bfseries#1};
    \else
    \node[above right,subsectionfg,anchor=west] at ($(number.east)+(0.1,0)$) {\large\bfseries#1};
    \fi
  \end{tikzpicture}
  \par
  \phantomsection
  \addcontentsline{toc}{subsection}{#1}
}

子子节样式

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 子子节样式

\renewcommand\subsubsection{
  \@ifstar
  \my@subsubsectionstar
  \my@subsubsection
}

\tikzstyle{subsubsectionstyle}=[
  left color=subsubsectionfg!50!white,
  right color=subsubsectionfg!100!white,
  text=Ivory,
  shape=trapezium,
  inner sep=5pt
]

\newcommand\my@subsubsection[1]{
  \stepcounter{subsubsection}
  \noindent  
  \begin{tikzpicture}
	\node[subsubsectionstyle] (number) {\bfseries\large\thesubsubsection};
	\node[subsubsectionfg, right of=number, anchor=west] {\large\bfseries#1};
  \end{tikzpicture}
  \par
  \phantomsection
  \addcontentsline{toc}{subsubsection}{\thesubsubsection~#1}
}

\newcommand\my@subsubsectionstar[1]{
  \noindent
  \begin{tikzpicture}
	\node[subsubsectionstyle] (number) {\bfseries\large\vphantom{1}};
	\node[subsubsectionfg, right of=number, anchor=west] {\large\bfseries#1};
  \end{tikzpicture}
  \par
  \phantomsection
  \addcontentsline{toc}{subsubsection}{#1}
}

\endinput

Last modified: Wednesday, 23 April 2025, 12:06 PM