给定 3 列,tcolorbox 框从第 2 列开始。为什么?

给定 3 列,tcolorbox 框从第 2 列开始。为什么?

考虑以下 LaTeX 文档:

\documentclass{article}
\usepackage{lipsum,multicol}
\usepackage[breakable]{tcolorbox}
\begin{document}

\begin{multicols*}{3}
A is for Amy who fell down the stairs.

\begin{tcolorbox}[title={Lorem Ipsum},breakable]
  \lipsum[1]
\end{tcolorbox}

B is for Basil assaulted by bears.
\end{multicols*}

\end{document}

这是它呈现为 pdf 的方式:

易碎 + 多色

为什么框从第二列开始?如何强制它从第一列的段落开始?


建议的解释以及我的保留意见

根据Sturm 教授的评论如下,上述行为不是一个错误;它是由于

tcolorbox不知道multicols环境内部的可用空间。

但是,然后考虑通过将 tcolorbox 的内容缩减为段落的第一句话而从原始文档获得的修改后的文档。 生成的 pdf 如下:

较短的 breakable + multicol

如果tcolorbox不知道multicols环境内的可用空间,那么为什么 tcolorbox 不像以前一样从第二列开始?

答案1

两个包在彼此不了解的情况下尝试将一个厨房分成几列,这两个包之间的交互存在限制,例如,如果multicol在平衡模式下运行,它只会在任何内部完成其魔力之后才进行平衡tcolorbox,因此只会看到留下的断点tcolorbox。因此,除非两个包真正互连(即一个实现另一个的功能),否则自动化的机会不大,但这不会发生。所以这意味着这里必须tcolorbox手动提供断点。

multicols*然而,在情况有些不同的情况下,因为tcolorbox可以知道可用的空间。然而,它只是假设它将是\textheight,因此表现出不受欢迎的行为。不要以为人们可以称其为漏洞tcolorbox但考虑到已经尝试意识到这一点,这是一个不必要的限制multicol

事实上,可用空间是已知的(或可能是):它\@colroom减去多列环境中已经排版的内容,即\pagetotal(只要我们在第一列)。如果我们进一步向下,则需要进行一定程度的调整,但正如下面的代码所示,这似乎是可行的。

现在我对 tcolorbox 内部结构了解不多(事实上我今天第一次看了代码)所以我的“修复”可能需要进一步调整,但方向可能没问题。

以下是代码和测试文件:

\documentclass{article}
\usepackage{lipsum,multicol}
\usepackage[breakable]{tcolorbox}

\makeatletter
\newif\iftcb@latermulticol  % are we in a later column?

% remaining height
\def\tcb@comp@h@page{%
  \tcb@breakat@next%
  \ifdim\tcb@breakat@dim>0pt\relax%
    \tcbdimto\tcb@h@page{\tcb@breakat@dim-\kvtcb@shrinkbreakgoal}%
  \else%
    \ifx\kvtcb@float\@empty%
      \iftcb@multicol%
      %
      % currently tcolorbox always assumes that \textheight is available
      %
      %        \tcbdimto\tcb@h@page{\textheight-\kvtcb@shrinkbreakgoal}%
      %
      % but we do know what is available inside a multicol:
      %
      % it is \@colroom minus what is already set (which is \pagetotal)
      %
      % However this is only true for the first column as multicol scans all
      % column material and only then breaks it into columns
      % So for the next columns we need to tell tcolorbox that the value
      % is \@colroom (without any substractions)
      %
      % Thus we distinguish the two cases via a boolean
      %
        \iftcb@latermulticol
          \tcbdimto\tcb@h@page{\@colroom-\kvtcb@shrinkbreakgoal}%
        \else
          \tcb@latermulticoltrue
          \ifdim\pagegoal=16383.99998pt
            \tcbdimto\tcb@h@page{\@colroom-\kvtcb@shrinkbreakgoal}%
          \else%
      %
          % If we start not in the first column then \pagetotal is already
          % the material for more than a column so we substract \@colroom
          % until we are in range (which is not quite accurate but close)
      %    
            \@tempdima\pagetotal
            \@whiledim \@tempdima>\@colroom \do{\advance\@tempdima-\@colroom}%
            \tcb@comp@compress%
            \tcbdimto\tcb@h@page{\@colroom-\@tempdima+\tcb@compress@height -\kvtcb@shrinkbreakgoal}%
          \fi%
        \fi
      %
      % end of mod
      %
      \else%
        \ifdim\pagegoal=16383.99998pt
          \tcbdimto\tcb@h@page{\vsize-\kvtcb@shrinkbreakgoal}% detects floating objects
        \else%
          \tcb@comp@compress%
          \tcbdimto\tcb@h@page{\pagegoal-\pagetotal+\tcb@compress@height-\kvtcb@shrinkbreakgoal}%
        \fi%
      \fi%
    \else%
      \tcbdimto\tcb@h@page{\textheight-\kvtcb@shrinkbreakgoal}%
    \fi%
  \fi%
}
\makeatother

\begin{document}

\begin{multicols*}{3}
  A is for Amy who fell down the stairs.

  \begin{tcolorbox}[title={Lorem Ipsum},breakable]
    \lipsum[1]
  \end{tcolorbox}

  B is for Basil assaulted by bears.
\end{multicols*}

\begin{multicols*}{3}
  Starting with tcolorbox in the second column \ldots
  Starting with tcolorbox in the second column \ldots
  Starting with tcolorbox in the second column \ldots
  Starting with tcolorbox in the second column \ldots
  Starting with tcolorbox in the second column \ldots
  Starting with tcolorbox in the second column \ldots
  Starting with tcolorbox in the second column \ldots

  \lipsum[1]

  \begin{tcolorbox}[title={Lorem Ipsum},breakable]
    \lipsum[1]
  \end{tcolorbox}

  B is for Basil assaulted by bears.
\end{multicols*}


The balancing multicol of course still fails without manual help as
that would require both packages interact with each other

\begin{multicols}{3}
  A is for Amy who fell down the stairs.

  \begin{tcolorbox}[title={Lorem Ipsum},breakable]
    \lipsum[1]
  \end{tcolorbox}

  B is for Basil assaulted by bears.
\end{multicols}

some more text

\end{document}

如果我们排版这个我们会得到以下三页:

在此处输入图片描述 在此处输入图片描述 在此处输入图片描述

答案2

基于 Frank Mittelbachs 补丁,我进行了大量实验,以获得一种可以multicols完全自动化地在环境内进行破解的算法。但我发现太多情况会欺骗自动化机制,而这种欺骗方式比没有自动化机制更糟糕。同时,我看不到未来会有任何成功。

尽管如此,半自动化破解还是可行的,这比旧实现更好。我改编了 Frank Mittelbach 的补丁,并为tcolorbox版本实现了一个更改版本4.10 (2017/07/05)

主要(新)特点是:

  • 默认断裂高度是当前的开始分页时的列高。如果列高在每一页和下一页之间发生变化,则默认分页高度不会改变(实际上,它会改变,但下一页的第一列不会改变)。

  • 第一个框部分的高度估计与 Frank Mittelbachs 补丁中一样。这个估计值可能太大,导致第一个框部分从当前列滑落到下一列。

为了补偿可能的命名快捷方式,break at可以添加。break at也进行了修改以支持更容易的更正。

我们来看一些示例代码:

\documentclass{article}
\usepackage{lipsum,multicol}
\usepackage[showframe]{geometry}
\usepackage[breakable]{tcolorbox}

\begin{document}

\begin{multicols*}{3}
  A is for Amy who fell down the stairs.

  \begin{tcolorbox}[title={Lorem Ipsum},breakable]
    \lipsum[1-2]
  \end{tcolorbox}

  B is for Basil assaulted by bears.
\end{multicols*}

\begin{multicols*}{3}
  \lipsum[1-3]

  \begin{tcolorbox}[title={Lorem Ipsum},breakable]
    \lipsum[1]
  \end{tcolorbox}

  B is for Basil assaulted by bears.
\end{multicols*}

The two examples above worked without manual help, but this will be true
only for lucky situations. If a multicols environment starts on one page
with previous content (like this one) and continues to a second page,
the automatism will fail.
In this case, use the \texttt{break at} option:

\begin{multicols*}{3}
  A is for Amy who fell down the stairs.
  \lipsum[1-2]

  \begin{tcolorbox}[title={Lorem Ipsum},breakable,height fixed for=first and middle,
    break at=-\baselineskip/0pt/\textheight,
  ]
    \lipsum[1-5]
  \end{tcolorbox}

  B is for Basil assaulted by bears.
\end{multicols*}

\end{document}

在此处输入图片描述 在此处输入图片描述 在此处输入图片描述 在此处输入图片描述

前两个multicols*带有内嵌 breakable 的环境tcolorbox不需要任何手动更正,但第三个环境就比较棘手了。在这里,添加了以下内容以获得(良好)结果:

break at=-\baselineskip/0pt/\textheight

含义如下:

  • -\baselineskip:第一列的大小按照预估空间减一 来确定\baselineskip,因为实际空间小于预估空间。在 版本之前4.10 (2017/07/05),负值的含义与 相同0pt

  • 0pt:第二列的大小可达到当前的列高。在 之前的版本中4.10 (2017/07/05)0pt表示\textheight

  • \textheight:第三列和所有后续列的大小都调整为\textheight,因为在我们的示例第 4 页上,列的高度发生了变化。

答案3

似乎环境tcolorbox内部之前的段落multicol打破了计算第一个片段高度并将其放置在第二列的方式tcolorbox。我认为这是一个错误,但我会等待其他评论/意见。同时,可以使用手动计算选项避免不良行为break at=

\documentclass{article}
\usepackage{lipsum,multicol}
\usepackage[breakable]{tcolorbox}
\begin{document}

\begin{multicols}{3}
A is for Amy who fell down the stairs.

\begin{tcolorbox}[title={Lorem Ipsum}, breakable, break at=18cm/0pt]
  \lipsum[1-2]
\end{tcolorbox}

B is for Basil assaulted by bears.
\end{multicols}

\end{document}

在此处输入图片描述

相关内容