为什么我的易碎 tcolorbox 会被覆盖?

为什么我的易碎 tcolorbox 会被覆盖?

我遇到过这样一种情况,即可拆分的 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 行。”

相关内容