LaTeX 实现各级章节标题内容左对齐

让各级标题的内容左对齐是一个比较常见的排版需求,在 Word 里可以通过制表符轻易实现。但在 LaTeX 中似乎没有什么现成的方法。google 一通,也只在 StackExchange 上找到一个很复杂的实现方式,不但依赖 KOMA-Script,还要自己码一大堆代码。

Word 里混乱复杂的多级列表设定和各种排版细节上的差强人意(例如标点压缩),总是让我受不了,想用 LaTeX 把工作上的合同重新排版一遍。合同中,把各级编号后的条款内容左对齐是最基本的排版需求。LaTeX 不可能连这么简单的事都搞不定吧……如鲠在喉,想了一个晚上终于搞通了。

左为默认状态下 LaTeX 的多级标题排版方式,即在编号后加一个固定空白。 右为排版目标,让所有级别的标题都左对齐。

思路是这样的:如果能把各个级别的章节编号全都放进统一固定长度的左右盒子里,就能保证章节名称的启始位置全都一致,实现左对齐。这样一来就必须修改\section\subsection等章节指令的内部定义。借助《LaTeX2e文类和宏包学习手册》和\show指令,得以一窥\section指令的源码:

% \section 宏在 article 文类中的定义:
\section=\long macro:
->\@startsection {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus -.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }

可以看到\section是通过\@startsection指令定义的。进一步查看\@startsection的定义:

\@startsection=macro:
#1#2#3#4#5#6->\if@noskipsec \leavevmode \fi 
\par \@tempskipa #4\relax \@afterindenttrue 
\ifdim \@tempskipa <\z@ \@tempskipa -\@tempskipa \@afterindentfalse \fi
\if@nobreak \everypar {}
\else \addpenalty \@secpenalty \addvspace \@tempskipa \fi 
\@ifstar {\@ssect {#3}{#4}{#5}{#6}}{\@dblarg {\@sect {#1}{#2}{#3}{#4}{#5}{#6}}}

忽略各种条件判断语句,其中最核心的是\@sect指令,进一步查看\@sect指令定义:

\@sect=macro:
#1#2#3#4#5#6[#7]#8->\ifnum #2>\c@secnumdepth \let \@svsec \@empty 
\else \refstepcounter {#1}\protected@edef \@svsec {\@seccntformat {#1}\relax }\fi 
\@tempskipa #5\relax 
\ifdim \@tempskipa >\z@
 \begingroup #6{\@hangfrom {\hskip #3\relax \@svsec }\interlinepenalty \@M #8\@@par }\endgroup \csname #1mark\endcsname {#7}
\addcontentsline {toc}{#1}{
\ifnum #2>\c@secnumdepth 
\else \protect \numberline {\csname the#1\endcsname }\fi #7}
\else \def \@svsechd {#6{\hskip #3\relax \@svsec #8}\csname #1mark\endcsname {#7}
\addcontentsline {toc}{#1}{
\ifnum #2>\c@secnumdepth \else \protect \numberline {\csname the#1\endcsname }\fi #7}}\fi 
\@xsect {#5}

可以发现其中输出章节编号的核心指令是\@seccntformat,进一步查看其定义:

\@seccntformat=macro:
#1->\csname the#1\endcsname \quad 

到此为止就可以破案了。\@seccntformat利用\csnamethe字符串与指令参数(即章节定义的名称,如sectionsubsection等)拼凑成了章节编号计数器输出命令(\thesection\thesubsection……),从而输出章节编号,并在其后加上一段\quad空白。我们只需要修改一下这个定义,将章节编号放进一个左右盒子里即可:

\makeatletter
\def\@seccntformat#1{\makebox[40pt][l]{\csname the#1\endcsname}}
\makeatother

通过修改定义,将章节编号放进了一个40pt宽度的盒子中。由于这一定义会影响所有级别章节的编号输出样式,就实现了所有级别的章节文字内容左对齐。而且因为这样的修改比较底层,不会和上层的各类宏包冲突,之后还能继续使用ctex等宏包进一步对章节标题的排版进行其他设置。

排版思路:将章节编号放进一个统一宽度的左右盒子中,此图中故意没有隐去盒子边框。

你可能感兴趣的:(LaTeX 实现各级章节标题内容左对齐)