0

I think I've stumbled upon a tcolorbox bug: whenever there are two consecutive breakable boxes, neither can fit unbroken in the current page, and the content of the first is unbreakable (e.g. an image) while the content of the second is breakable (e.g. text), then the first is moved to the next page as expected, but for some reason, the second one is not broken and end-up overflowing from the page. Making the first box unbreakable (which should change basically nothing since it can not be broken) fixes the problem, which makes me think that this is due to tcolorbox somehow wrongly applying the decision to not break the first box to the second box.

The actual use case is a PhD thesis where every figure, theorem (and fact, proposition, remark, etc.) and proof is in a breakable tcolorbox. This problem happens at unexpected places because the figures float while the theorems do not, which makes manually making some boxes unbreakable unmanageable.

I've looked at the code for the beakable, tried changing the values of booleans \tcb@break@allowedtrue and \tcb@ignorenobreaktrue and placing the box in a group (to prevent value changes from leaking to the other box), but this had no effect.

\documentclass{article}
\usepackage[most]{tcolorbox}
\usepackage{afterpage}
\usepackage{lipsum}

\tcbset{enhanced}

\newcommand{\breakablecontent}{\lipsum[1-12]}
\newcommand{\nonbreakablecontent}{\rule{\columnwidth}{\columnwidth}}

\newcommand{\mytest}[1]{
  \lipsum[1-3]
  \afterpage{
    \begin{tcolorbox}[breakable=true]
      \breakablecontent
    \end{tcolorbox}
  }
  \begin{tcolorbox}[breakable=#1]
    \nonbreakablecontent
  \end{tcolorbox}
}

% Naive Attempt to fix this:
%\makeatletter
%\renewcommand{\mytest}[1]{
%  \lipsum[1-3]
%  \afterpage{
%    \tcb@break@allowedtrue\tcb@ignorenobreaktrue
%    \begingroup
%    \begin{tcolorbox}[breakable=true]
%      \breakablecontent
%    \end{tcolorbox}
%    \endgroup
%    \tcb@break@allowedtrue\tcb@ignorenobreaktrue
%  }
%  \tcb@break@allowedtrue\tcb@ignorenobreaktrue
%  \begin{tcolorbox}[breakable=#1]
%    \nonbreakablecontent
%  \end{tcolorbox}
%}
%\makeatother

\begin{document}

\section{Expected behavior}
\mytest{false}

\clearpage

\section{Unexpected behavior}
\mytest{true}

\end{document}
10
  • 1
    I think, the problem really is related to \afterpage where you place the first tcolorbox in. Without this, the breakpoints work as expected. What is the reason you use this? Would \clearpage be a workaround for you, maybe? Commented May 26, 2023 at 11:01
  • @JasperHabicht Right. I use this because I want some figures to be in landscape, but did not manage to make this work with floating figures, so I do \afterpage{\begin{landscape}\begin{figure}[H]. Maybe I should just use the landscape option of tcolorbox to rotate only the figure, and then store lists of pages I want to rotate back and use something similar to tex.stackexchange.com/questions/451418/…
    – xavierm02
    Commented May 26, 2023 at 12:03
  • But there ought to be some simpler way of doing it. Surely, saving the state of some well-chosen tcolorbox variables just before the afterpage and restoring it at the beginning of the afterpage should work.
    – xavierm02
    Commented May 26, 2023 at 12:07
  • There's also the option of using \savebox and \usebox for the second box, which prevents any interleaving with the first box and hence fixes the problem for this example. But I have use cases where the afterpage figure takes several pages so this would not always work (as can be seen if we replace the content of the first box with \nonbreakablecontent\\\nonbreakablecontent\\\nonbreakablecontent\\\nonbreakablecontent).
    – xavierm02
    Commented May 26, 2023 at 12:20
  • 1
    use the magazine library to split and store the pieces and then output them manually in the order your want. Do not rely on afterpage, it inserts the tcolorbox in the output routine and that confuses tcolorbox which hasn't done all the needed cleaning up yet. Commented May 26, 2023 at 14:49

2 Answers 2

2

I think, the problem really is related to \afterpage where you place the first tcolorbox in. Without this, the breakpoints work as expected. I am unsure why you need this. Maybe a workaround could be to place a simple \clearpage right before the following tcolorbox?

MWE:

\documentclass{article}
\usepackage[most]{tcolorbox}
\usepackage{lipsum}

\tcbset{enhanced}

\newcommand{\breakablecontent}{\lipsum[1-12]}
\newcommand{\nonbreakablecontent}{\rule{\columnwidth}{\columnwidth}}

\newcommand{\mytest}[1]{
  \lipsum[1-3]
  \clearpage
  \begin{tcolorbox}[breakable=true]
    \breakablecontent
  \end{tcolorbox}
  \clearpage
  \begin{tcolorbox}[breakable=#1]
    \nonbreakablecontent
  \end{tcolorbox}
}

\begin{document}

\section{Expected behavior}
\mytest{false}

\clearpage

\section{Unexpected behavior}
\mytest{true}

\end{document}
2

Using the magazine library as suggested by Ulrike Fischer fixes the overflow problem but the unbreakable content is inexplicably shifted downwards, outside of its box. Using floats instead of afterpage works.

\documentclass{article}
\usepackage[most]{tcolorbox}
\usepackage{afterpage}
\usepackage{lipsum}

\tcbset{enhanced}

\newcommand{\breakablecontent}{\lipsum[1-12]}
\newcommand{\nonbreakablecontent}{\rule{\columnwidth}{\columnwidth}}

\newboxarray{a}

% Does not work weirdly
\newcommand{\mytest}[1]{
  \lipsum[1-3]\\
  \begin{tcolorbox}[breakable=true, reset and store to box array=a]
    \breakablecontent
  \end{tcolorbox}
  \afterpage{
    \consumeboxarray[a]{1}{}
    \consumeboxarray[a]{2}{}
    \consumeboxarray[a]{3}{}
  }
  \begin{tcolorbox}[breakable=#1]
    \nonbreakablecontent
  \end{tcolorbox}
}

% Works
\renewcommand{\mytest}[1]{
  \lipsum[1-3]\\
  \begin{tcolorbox}[breakable=true, reset and store to box array=a]
    \breakablecontent
  \end{tcolorbox}
  \begin{figure}[p]\consumeboxarray[a]{1}{}\end{figure}
  \begin{figure}[p]\consumeboxarray[a]{2}{}\end{figure}
  \begin{figure}[p]\consumeboxarray[a]{3}{}\end{figure}
  \begin{tcolorbox}[breakable=#1]
    \nonbreakablecontent
  \end{tcolorbox}
}

\begin{document}

\section{Expected behavior}
\mytest{false}

\clearpage

\section{Unexpected behavior}
\mytest{true}

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .