我遇到过这样一种情况,即可拆分的 tcolorbox 被后面的文本覆盖。我认为垂直可拉伸空间排列得恰到好处,因此分页和拆分框算法会混淆。我意识到我可以在框后面放置一个 \clearpage,但这需要我注意到这种情况发生在一个相当长的文档中(如果框移动,那么 \clearpage 就是不正确的)。
以下文件:
\documentclass[10pt]{article}
\usepackage[textheight=7in,textwidth=320pt]{geometry}
\usepackage{tcolorbox}
\tcbuselibrary{breakable}
\newcommand{\onelineoftext}{this is just about one line of text after I make it long enough for my purposes}
\usepackage{lipsum}
\begin{document}
\lipsum[1-4]
\begin{tcolorbox}[size=minimal,breakable]
One\\Two\\Three
% the page breaks here
\begin{enumerate}
\item one
\item two
\item three
\item four
\end{enumerate}
Text
\begin{enumerate}
\item \onelineoftext\onelineoftext\onelineoftext
\onelineoftext\onelineoftext\onelineoftext\onelineoftext
\onelineoftext\onelineoftext\onelineoftext\onelineoftext
\item One\\two
\item Displayed equation
\[\lim_{x\to0}\cos\cos\cos\cos\cos\frac00\]
\item \onelineoftext\onelineoftext\onelineoftext\onelineoftext
\[\lim_x e^x\]
One
\item One\\two
\[\frac00\]
This text will be overwritten by the next paragraph and completely covered.
I don't understand why.
It seems to involve lots of vertical spacing that's just right,
so I can't eliminate much else.
\end{enumerate}
\end{tcolorbox}
%\clearpage % solves this page, but not the underlying problem
\onelineoftext\onelineoftext\onelineoftext\onelineoftext
\end{document}
第二页底部有以下内容(没有坏框)
我怎样才能防止这种重叠发生,或者至少让 TeX 警告我出现了问题?
更新
来自@muzimuzhiZ: 下面是一个简化的示例,显示此问题可能是由于 中的可收缩空间过多而导致的tcolorbox
。后面的文本tcolorbox
为蓝色,以强调重叠。
\documentclass{article}
\usepackage[breakable]{tcolorbox}
\usepackage{lipsum}
\begin{document}
\lipsum[1-4]
\begin{tcolorbox}[size=minimal,breakable]
\begin{enumerate}
\item
\lipsum[1-3]
\vskip 60pt plus 0pt minus 100pt
\lipsum[1-2]
\end{enumerate}
\end{tcolorbox}
\color{blue}\lipsum[1]
\end{document}
答案1
令人惊讶的是,我以前没有遇到过这种情况。
正如之前所评论的,框内似乎有太多可缩小的空间。拆分算法检测到框无法进一步拆分,但最终的框似乎太大而无法放在页面上(这里并非如此)。因此,最后一个框部分的边界框会变小以适合页面(否则我们会得到一个讨厌的空白页)。
这里,减少的幅度太大,导致出现重叠。
最好,中断算法应该更加狡猾(?!),但至少我可以提供一个\clearpage
自动插入的解决方案:
\makeatletter
\def\tcb@split@force@last{%
\tcb@split@setstate@last%
\ifdim\tcb@h@total>\tcb@h@page\relax%
\gdef\tcb@after@lastbox{\clearpage}%
\tcbdimto\kvtcb@bbbottom{\kvtcb@bbbottom+\tcb@h@page-\tcb@h@total}%
\fi%
}
\makeatother
此补丁应该可以解决问题。唯一的(小)缺点是它会删除由该after
键给出的用户代码。但恕我直言,该键用于框后的空格,与分页符无关。
答案2
我还没有找到防止重叠发生的方法,但我已经想出了如何知道它是否发生(有点)。这个想法是调用,\pdfsavepos
这样\pdflastypos
就知道 tcolorbox 的结尾和后面的内容的开头。然后我们可以比较它们,如果出现问题,则发出警告。唯一的缺点是使用 tcolorbox 框内容添加钩子会导致内容移动一行。
以下文件:
\documentclass{article}
\usepackage[breakable]{tcolorbox}
\usepackage{etoolbox}
\usepackage{lipsum}
\newcommand{\boxendpage}{-1}
\newcommand{\boxendypos}{-1}
\newcommand{\boxendat}[2]{%
\renewcommand{\boxendpage}{#1}%
\renewcommand{\boxendypos}{#2}%
}
\newcommand{\afterboxat}[3]{}%
\newcounter{warnlineno}
\AtEndDocument{%
\renewcommand{\afterboxat}[3]{%
\ifboolexpr{ test{ \ifnumequal{#1}{\boxendpage} }
and test{ \ifnumgreater{#2}{\boxendypos} } }{%
\setcounter{warnlineno}{#3}
\addtocounter{warnlineno}{-1}
\typeout{^^JLaTeX Warning: box overlaps on page #1, near line \arabic{warnlineno}.}%
}{}%
}%
}
\makeatletter
\newcommand{\markboxend}{%
\unskip%
\pdfsavepos%
\write\@auxout{\string\boxendat{\thepage}{\the\pdflastypos}}%
}
\newcommand{\markafterbox}{%
\pdfsavepos%
\write\@auxout{\string\afterboxat{\thepage}{\the\pdflastypos}{\the\inputlineno}}%
}
\makeatother
\begin{document}
\lipsum[1-4]
\begin{tcolorbox}[size=minimal,breakable,
after upper=\markboxend,after lower=\markboxend,after=\markafterbox
]
\begin{enumerate}
\item
\lipsum[1-3]
\vskip 60pt plus 0pt minus 60pt
\lipsum[1-2]
\end{enumerate}
\end{tcolorbox}
\color{blue}\lipsum[1] % line 56
\end{document}
输出与上面的输出略有不同:
但是日志文件现在显示“LaTeX 警告:框在第 2 页重叠,靠近第 56 行。”