我对理解 LaTeX 如何排版文档存在根本性的问题。考虑一下我的代码
\documentclass{article}
\usepackage[margin = 0.75in]{geometry}
\begin{document}
\section*{ABC}
abc
\section*{ABC}
\begin{itemize}
\item abc
\end{itemize}
\textbf{ABC}\\
abc\\
\textbf{ABC}\\
\begin{itemize}
\item abc
\end{itemize}
\end{document}
它产生的输出是:-
现在这从根本上来说是个问题。当我改变
\section*{ABC}
abc
到
\section*{ABC}
\begin{itemize}
\item abc
\end{itemize}
那么只有 abc 旁边会出现一个项目符号,而格式没有任何变化。
但是,当我在新行之后执行相同的操作时,如代码中所示
\textbf{ABC}\\
abc\\
\textbf{ABC}\\
\begin{itemize}
\item abc
\end{itemize}
然后由于某种原因,itemize 在呈现列表之前添加了一个新行。为什么?
答案1
让我们看看当你输入 时会发生什么\begin{itemize
。现在应该变成\itemize
,而\end{itemize}
变成\enditemize
。让我们看看\itemize
会发生什么:
\def\itemize{%
\ifnum \@itemdepth >\thr@@\@toodeep\else
\advance\@itemdepth\@ne
\edef\@itemitem{labelitem\romannumeral\the\@itemdepth}%
\expandafter
\list
\csname\@itemitem\endcsname
{\def\makelabel##1{\hss\llap{##1}}}%
\fi}
这是从latex.ltx
LaTeX 内核定义文件 中获取的。因此,它会检查您是否超出了 的第三级itemize
,如果超出,则发出错误\@toodeep
,否则,它会推进该级别的计数器itemize
,并将 定义为罗马数字的加号\@itemitem
。然后,它使用带有参数 的命令,即,例如,如果为 1,这就是 的原因,它需要在 之前进行扩展,第二个参数是,其中是一个变量 space,它决定了项目标签的放置位置,并且意味着标签可以超出左边距。所以让我们再次从 中查看。labelitem
\@itemdepth
\list
\csname\@itemitem\endcsname
\<whatever there is in @itemitem>
\labelitemi
\@itemdepth
\expandafter
\@itemitem
\list
{\def\makelabel##1{\hss\llap{##1}}
\hss
\llap
\list
latex.ltx
\def\list#1#2{%
\ifnum \@listdepth >5\relax
\@toodeep
\else
\global\advance\@listdepth\@ne
\fi
\rightmargin\z@
\listparindent\z@
\itemindent\z@
\csname @list\romannumeral\the\@listdepth\endcsname
\def\@itemlabel{#1}%
\let\makelabel\@mklab
\@nmbrlistfalse
#2\relax
\@trivlist
\parskip\parsep
\parindent\listparindent
\advance\linewidth -\rightmargin
\advance\linewidth -\leftmargin
\advance\@totalleftmargin \leftmargin
\parshape \@ne \@totalleftmargin \linewidth
\ignorespaces}
同样,会检查您是否嵌套了 5 个以上的列表,如果是,则有\@toodeep
,否则我们将嵌套列表的数量增加\@ne
,即 1。然后我们将三个长度设置为 0(\z@
为0pt
),然后使用命令\@list<roman numeral of list depth>
(例如,\@listi
如果我们处于嵌套的第一级)。\@listi
等等不在latex.ltx
,也不在plain.tex
或中list.tex
,所以我不知道在哪里看。\@itemlabel
定义为第一个参数,然后\makelabel
设置为\@mklab
,即\def\@mklab#1{\hfil #1}
。条件\@nmbrlist
为假,执行参数 2,可能\relax
将其与后面的内容分开,然后\@trivlist
执行,然后有几个长度分配,然后是\ignorespaces
。现在\@trivlist
,再次在 中latex.ltx
,定义如下:
\def\@trivlist{%
\if@noskipsec \leavevmode \fi
\@topsepadd \topsep
\ifvmode
\advance\@topsepadd \partopsep
\else
\unskip \par
\fi
\if@inlabel
\@noparitemtrue
\@noparlisttrue
\else
\if@newlist \@noitemerr \fi
\@noparlistfalse
\@topsep \@topsepadd
\fi
\advance\@topsep \parskip
\leftskip \z@skip
\rightskip \@rightskip
\parfillskip \@flushglue
\par@deathcycles \z@
\@setpar{\if@newlist
\advance\par@deathcycles \@ne
\ifnum \par@deathcycles >\@m
\@noitemerr
{\@@par}%
\fi
\else
{\@@par}%
\fi}%
\global \@newlisttrue
\@outerparskip \parskip}
我不会尝试解释这到底是做什么的。我只看到\@newlisttrue
执行了。\item
除了一些无趣的事情之外,还调用了\@item
,即:
\def\@item[#1]{%
\if@noparitem
\@donoparitem
\else
\if@inlabel
\indent \par
\fi
\ifhmode
\unskip\unskip \par
\fi
\if@newlist
\if@nobreak
\@nbitem
\else
\addpenalty\@beginparpenalty
\addvspace\@topsep
\addvspace{-\parskip}%
\fi
\else
\addpenalty\@itempenalty
\addvspace\itemsep
\fi
\global\@inlabeltrue
\fi
[…]
}
对于\@newlisttrue
,我们\@topsep
添加了 垂直空间,假设\@nobreakfalse
,这给了我们垂直空间。在 的省略部分\@item
有一个\@newlisttrue
,这意味着以下项目只有\itemsep
垂直空间。事实上,\@donoparitem
有一个\vskip\@tempskipa
,这给了额外的垂直空间。当你有两个连续的列表时使用它,因为中间没有“段落”,也许在 之后\\
,但无论如何它只是相对于 多了 2pt \@topsep
。所以如果你在标题中给出[-10pt]
可选参数\\
,空间应该会消失。无论如何,正如我在评论中所说,\subsubsection
可能是一个更好的主意,或者如果你有这个标题格式的命令,你可能想要制作一个没有 的星号变体\\
。至于“它并不总是有换行符”部分,我们可以看看 的定义\section
。我将在这里复制课堂上的一个report
:
\newcommand\section{\@startsection {section}{1}{\z@}%
{-3.5ex \@plus -1ex \@minus -.2ex}%
{2.3ex \@plus.2ex}%
{\normalfont\Large\bfseries}}
因此本质上是对 的调用\@startsection
。据我所知,该命令直接执行的操作与我们无关。它以调用\@sect
:结束\@sect{#1}{#2}{#3}{#4}{#5}{#6}
。查看 的定义\@sect
,似乎无论如何都不会影响\item
或\@item
或\@donoparitem
。所以我们到了最后,看到\@xsect{#5}
。同样,这一切让我们感兴趣的是\@tempskipa #1\relax
。无论如何,它似乎设置了,正如一个简单的测试所证明的那样。那么让我看一下的假设中\@noparitemfalse
的 的定义。在命令之后,一个简单的测试显示为真,而 定义的上述部分中的其他条件都是假的。这意味着该部分所做的只是和。但这不是的错。所以它一定是默认值,其他命令会处理这些条件。这意味着回答这个问题会\@item
\@noparitemfalse
\section
\ifhmode
\@item
\unskip\unskip \par
\global\@inlabeltrue
\section
非常很复杂,需要调查这些条件的每一个用法。所以我不能结束这个。这就是“为什么会发生这种情况”的部分,或者说它的开始。
至于“我该如何解决这个问题”部分,请尝试以下操作:
\documentclass[a4paper]{report}
\makeatletter
\newcommand{\header}{\@ifstar{\@header}{\he@der}}
\newcommand{\@header}[1]{\textbf{#1}\hfill2014-15\hfil}
\newcommand{\he@der}[1]{\textbf{#1}\hfill2014-15\\}
\makeatother
\begin{document}
\noindent\header{Header 1}
Text for header 1, no itemize. \\
\header*{Header 2}
\begin{itemize}
\item Here is a Header with itemize. As you can see, no extra space is produced, and no extra vertical space is added.
\item Just remember the star after \verb"header" in this case.
\end{itemize}
Now let's put a simple paragraph: Lorem ipsum dolor sit amet, consectetuer and so on. \\
\header{Header 3}
Nothing strange happens at all. I hope this solves your problem. Naturally, you can add the \verb"\noindent" to the command definition, to avoid the \verb"\parindent" for a header. You can also add a \verb"\par" or \verb"\\" before the header.
\end{document}
通过这个 MWE,我得到:
如果这不是您想要的格式,您可以告诉我。无论如何,额外的空间不存在,并且额外的空间itemize
不存在。当然,标题被视为文本,因此 itemize 和标题之间有垂直空间。如果您不想要那样,我可以尝试干预上面提到的那些条件,或者您可以添加一个\vspace
to \header
,以便它只在您希望它出现时出现。
答案2
\documentclass{article}
\usepackage[margin = 0.75in]{geometry}
\begin{document}
\section*{ABC}
abc
\section*{ABC}
This is a really long paragraph depicting how \LaTeX\ typesets documents. This is a really long paragraph depicting how \LaTeX\ typesets documents. This is a really long paragraph depicting how \LaTeX\ typesets documents. This is a really long paragraph depicting how \LaTeX\ typesets documents.
\begin{itemize}
\item abc
\end{itemize}
This is a really long paragraph that does not get indented because \LaTeX\ just left vertical mode from the \texttt{itemize} environment. This is a really long paragraph that does not get indented because \LaTeX\ just left vertical mode from the \texttt{itemize} environment. This is a really long paragraph that does not get indented because \LaTeX\ just left vertical mode from the \texttt{itemize} environment.
This is a really long paragraph that shows how a whitespace between two paragraphs causes the second paragraph to get indented. No further formatting is needed. This is a really long paragraph that shows how a whitespace between two paragraphs causes the second paragraph to get indented. No further formatting is needed. This is a really long paragraph that shows how a whitespace between two paragraphs causes the second paragraph to get indented. No further formatting is needed.
A double slash \texttt{\textbackslash\textbackslash} forces a line break. A forced line break with the \texttt{itemize} environment subsequent thereto will first cause a line break, then \LaTeX\ will go into vertical mode to typeset the items. This involves an operation in vertical mode \emph{twice} rather than \emph{once}, as you intended it: \\
\begin{itemize}
\item abc
\end{itemize}
Ufff, what an ugly space! Lesson learnt, I'd say!
\end{document}