4

Is there a way to produce unbalanced columns inside a minipage? Alternatively, is there any (simple) way to customise multicol to allow \begin{multicols*} to be used in boxes with a known height??

In my example, the minipage is 7cm high and I would like the first column to be full.

\documentclass{article}
\usepackage{kantlipsum}
\usepackage{multicol}
\begin{document}
    \section{A heading that spans two columns...}
    \begin{minipage}[t][7cm]{\linewidth}
        \begin{multicols}{2}
            \subsection{Kant 1}
            \kant[1]
        \end{multicols}
    \end{minipage}
    \subsection{Kant 2}
    \kant[2]
\end{document}

Instead the following is produced:

enter image description here

  • Oddly, multicols* doesn't work here. One could compute the remaining space and add a\rule{0pt}{...} to the end, but that would be about a complicated as using \vsplit and not as good. – John Kormylo Aug 30 '18 at 2:25
3

The key is the TeX primitive \vsplit. The columns are expanded in \parboxes using \unvbox so as to correctly fill the space using glue. We do NOT want the columns to be aligned by either the top or bottom baseline. (Okay, the bottom actually works, but why risk it?)

Registers \vsize, \columnwidth, \box0 and \box1 are only changed local to the minipage. Fixing the height of the minipage is redundant.

Note: For narrow columns \sloppy is SOP. You will also need some glue in every full column.

\documentclass{article}
\usepackage{kantlipsum}
\usepackage{multicol}
\begin{document}
    \section{A heading that spans two columns...}
    \begin{minipage}{\linewidth}
        \vsize=7cm
        \columnwidth=\dimexpr 0.5\textwidth - 0.5\columnsep\relax
        \setbox0=\vbox{\hsize=\columnwidth
            \sloppy
            \addtolength{\baselineskip}{0pt plus 1pt minus .5pt}% usually glue comes from \parskip
            \subsection{Kant 1}
            \kant[1]}%
        \ifdim\ht0<\vsize
            \parbox[c][\vsize][t]{\columnwidth}{\unvbox0}
        \else
            \setbox1=\vsplit0 to \vsize 
            \parbox[c][\vsize][s]{\columnwidth}{\unvbox1}\hfill
            \parbox[c][\vsize][t]{\columnwidth}{\unvbox0}
        \fi
    \end{minipage}
    \section{A heading that spans three columns...}
    \begin{minipage}{\linewidth}
        \vsize=7cm
        \columnwidth=\dimexpr 0.333\textwidth - 0.667\columnsep\relax
        \setbox0=\vbox{\hsize=\columnwidth
            \sloppy
            \addtolength{\baselineskip}{0pt plus 1pt minus .5pt}% usually glue comes from \parskip
            \subsection{Kant 1}
            \kant[1]}%
        \ifdim\ht0<\vsize
            \parbox[c][\vsize][t]{\columnwidth}{\unvbox0}
        \else
            \setbox1=\vsplit0 to \vsize 
            \parbox[c][\vsize][s]{\columnwidth}{\unvbox1}\hspace{\columnsep}%
            \ifdim\ht0<\vsize
                \parbox[c][\vsize][t]{\columnwidth}{\unvbox0}
            \else
                \setbox1=\vsplit0 to \vsize 
                \parbox[c][\vsize][s]{\columnwidth}{\unvbox1}\hfill
                \parbox[c][\vsize][t]{\columnwidth}{\unvbox0}
            \fi
        \fi
    \end{minipage}
\end{document}

demo

  • Could you please post similar solution for 3 columns? Thanks in advance! – konserw Sep 6 '18 at 16:12
0

The extra optional arguments to minipage or \parbox where added to the LaTeX kernel when LaTeX 2e was written. Essentially what they do is to produce a \vbox to <height>. Unfortunately, inside this box it is not clear for any code (unless I'm totally mistaken that it is run in a box with a defined height, but only that it is run in a box. Looking at \height doesn't help as you could nest boxes and thus see the wrong \height.

So basically, while it is clear for a human that we are inside such a box, code excuted inside doesn't and this is why multicol simply determines, ah box -> balancing is needed as we don't know where the bottom is.

Second reason (to be honest) I never thought about those extra optional arguments when writing the multicols* code. So bottom line, it might be possible, well it is really (see @John's code in his answer) but it may not be trivial to do that automatically in multicols as you need to somehow pass the infor that this is a box of height 7cm into the code.

So as of today, no automatic solution (as you see John also passes this knowledge manually to his code).

  • Could you please add such option? Even if minipage height would be passed as additional argument to multicols* it would save my day! :) – konserw Sep 6 '18 at 16:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.