1

The simplest way to create a list with two columns of different widths is probably by splitting it into two minipages:

However, the right column's text is taller than the left column. I want the left list to stretch evenly (just between items, no interline space increase within an item) and align to the bottom of the right column. This can be achieved with multicol, but then the columns will have the same width (and there seems to be no way around that):

\documentclass{article}
\usepackage{lipsum}
\usepackage{multicol}
\begin{document}
\begin{multicols}{2}
\begin{description}
    \item \lipsum[1][1]
    \item \lipsum[1][2]
    \item \lipsum[1][3]
    \item \lipsum[1][4]
    \item \lipsum[1][5-6]
    \item \lipsum[1][7-9]
\end{description}
\end{multicols}
\end{document}

Is there an easy way to do this with two columns of different widths?

  • 1
    Welcome! You don't care if the baselines of the texts are aligned except for the first and last lines? – cfr Dec 12 '23 at 01:20
  • @cfr yes, that's right. – The Footprint Dec 12 '23 at 01:25
  • That's very poor typography .... – cfr Dec 12 '23 at 01:30
  • For my use case, the height difference between columns is more annoying. And I can't have both right? – The Footprint Dec 12 '23 at 01:33
  • 1
    You should be able to have both if you don't insist on even stretching. That is, if you can skip whole lines, rather than stretching the space between the lines, it ought to be possible to keep lines aligned. (Note this is a theoretical claim. I am not sure how easy it would be to implement.) – cfr Dec 12 '23 at 01:45
  • Will you manually specify the text that goes into each of the two columns, or do you expect to find the "break point" automatically? – Willie Wong Dec 12 '23 at 02:05
  • @WillieWong automatically is better, but manual is fine. – The Footprint Dec 12 '23 at 02:08

2 Answers2

2

For the more modest goal of stretching the gaps between items, and using manual breaking of columns, you can measure the heights and set itemsep=\fill using an appropriate minipage. (I don't have latin hyphenation on my laptop, so apologies for the bad hyphenation in the blind text.)

enter image description here

Code (more a proof-of-concept; not really optimized in anyway)

\documentclass{article}
\usepackage{lipsum}
\usepackage{enumitem}
\usepackage{environ}

%%%% \makeatletter \newsavebox{@lefttextbox} \newsavebox{@righttextbox} \newlength@leftboxwidth \newlength@rightboxwidth \newlength@leftboxmeasureht \newlength@rightboxmeasureht \newlength@largerheight \NewEnviron{leftbody}{% \expandafter\gdef\expandafter@leftbodycontent\expandafter{\BODY}% \savebox{@lefttextbox}{% \begin{minipage}[b]{@leftboxwidth} \BODY \end{minipage}% }% \global@leftboxmeasureht=\ht@lefttextbox\relax% } \NewEnviron{rightbody}{% \expandafter\gdef\expandafter@rightbodycontent\expandafter{\BODY}% \savebox{@righttextbox}{% \begin{minipage}[b]{@rightboxwidth} \BODY \end{minipage}% }% \global@rightboxmeasureht=\ht@righttextbox\relax% } \newenvironment{unevencols}[2]{% args: width of the two columns \setlength{@leftboxwidth}{#1}% \setlength{@rightboxwidth}{#2}% }{% \ifdim@leftboxmeasureht<@rightboxmeasureht\relax% \setlength{@largerheight}{@rightboxmeasureht}% \else \setlength{@largerheight}{@leftboxmeasureht}% \fi \begin{trivlist}\item\begin{minipage}[t][@largerheight]{@leftboxwidth} \setlist{itemsep=\fill}% @leftbodycontent% \end{minipage} \begin{minipage}[t][@largerheight]{@rightboxwidth} \setlist{itemsep=\fill}% @rightbodycontent% \end{minipage} \end{trivlist} } \makeatother %%%%

\begin{document}

\lipsum[2] \begin{unevencols}{0.59\textwidth}{0.4\textwidth} \begin{leftbody} \begin{description} \item \lipsum[1][1] \item \lipsum[1][2] \item \lipsum[1][3] \item \lipsum[1][4] \end{description} \end{leftbody}% \begin{rightbody} \begin{description} \item \lipsum[1][5-6] \item \lipsum[1][7-9] \end{description} \end{rightbody} \end{unevencols} \lipsum[3]

\end{document}

Willie Wong
  • 24,733
  • 8
  • 74
  • 106
  • This is really good and instructive, thanks! I have only one minor problem with your solution: it seems that the baseline space after the unevencols environment is shorter, as if the bottom of the minipages were a little above the last line of printed text. – The Footprint Dec 12 '23 at 15:00
  • 1
    Your observation is half correct: the space after the unevencols environment is shorter; but this has nothing to do with the bottom of the minipages. The issue is basically the same as https://tex.stackexchange.com/a/480369/119. You can ensure that the two spaces are the same if in the code for unevencols you replace the minipage alignment from [t] to [c]. The down side is that this way, both are a little bit too small (by equal amounts). (Basically, currently you have a \baselineskip above and a \linsekip below; changing to [c] will give both \lineskip.) – Willie Wong Dec 13 '23 at 04:01
  • Here's the thing. I would like to get the same spacing as any inline element, so I eliminated the trivlist and inserted new lines before and after the unevencols. But I have managed to get correct spacing only before the unevencols with [t] alignment. Now the space after the environment is actually a bit larger than the baselineskip. With both [c] and [b], the space before gets too small and the space after is even bigger. What can I do to get uniform spacing? – The Footprint Dec 13 '23 at 12:31
  • Wow, getting equal spacing before and after a minipage seems way harder than it should. There are several threads with solutions, for example https://tex.stackexchange.com/questions/349178/vertical-space-after-minipage-edit-in-an-environment – The Footprint Dec 13 '23 at 18:13
  • 1
    @TheFootprint please see my second answer; it also fixes a bug with the first one where if your text is nongeneric (not having ascenders/descenders) than the alignment will be wrong. – Willie Wong Dec 14 '23 at 03:31
1

A new version

The OP also wanted to remove and balance the spaces before and after the environment. Normally this is hard with minipages, but in our case we know exactly how tall the minipage is going to be and where the various baselines ought to be, so we can cheat.

While doing this, I also discovered a bug with my original answer: it doesn't correctly factor in when the first line and the bottom line are not generic. (For example, you can see what happens if you replace the content of the rightbody with \item aaa \item aaa. The minipage used will be too large to get the correct alignment.)

What we need to do:

  • Set \topsep and \partopsep to 0pt so that \trivlist doesn't add extra space.
  • Correctly compute the space required by measuring for each box: the height of the first line, the depth of the last line, and the "body" height (everything below the baseline of the first line and above the baseline of the bottom line).
  • Convince TeX to not use the minipage to compute the line spacings. To do this I will \smash the minipages. I will insert a rule where the first line is (with height given by the larger of the top-line-heights of the top boxes), then \vskip an appropriate amount (the "body height" minus one \baselineskip), and insert another rule (descending below the baseline the larger of the bottom-depths of the two boxes). This way the interline spacing before and after the minipages will be computed exactly as if the content were showing up "in line".
  • Additional cosmetic change: I placed an \hfill between the two minipages to spread them out if the specified widths do not add up to full width.
% Note: if using the lua-visual-debug package, build with lualatex
% If comment out the package, you can build with pdflatex
\documentclass{article}
\usepackage{lua-visual-debug} % used to show the boxes so that the proper alignment is clear
\usepackage{lipsum}
\usepackage{enumitem}
\usepackage{environ}

%%%% \makeatletter \newlength@LBwd \newlength@RBwd \newlength@LBtopht \newlength@LBtopdp \newlength@LBbodht \newlength@LBbotdp \newlength@RBtopht \newlength@RBtopdp \newlength@RBbodht \newlength@RBbotdp \NewEnviron{leftbody}{% \expandafter\gdef\expandafter@leftbodycontent\expandafter{\BODY}% \sbox0{% \begin{minipage}[t]{@LBwd} \BODY \end{minipage}% }% \global@LBtopht=\ht0\relax% \global@LBtopdp=\dp0\relax% \sbox0{% \begin{minipage}[b]{@LBwd} \BODY \end{minipage}% } \global@LBbotdp=\dp0\relax% \global@LBbodht=\dimexpr@LBtopdp-@LBbotdp\relax% } \NewEnviron{rightbody}{% \expandafter\gdef\expandafter@rightbodycontent\expandafter{\BODY}% \sbox0{% \begin{minipage}[t]{@RBwd} \BODY \end{minipage}% }% \global@RBtopht=\ht0\relax% \global@RBtopdp=\dp0\relax% \sbox0{% \begin{minipage}[b]{@RBwd} \BODY \end{minipage}% } \global@RBbotdp=\dp0\relax% \global@RBbodht=\dimexpr@RBtopdp-@RBbotdp\relax% }

\newlength@pokeabove \newlength@pokebelow \newenvironment{unevencols}[2]{% args: width of the two columns \setlength{@LBwd}{#1}% \setlength{@RBwd}{#2}% }{% \ifdim@LBbodht<@RBbodht\relax% @LBbodht=@RBbodht\relax% \else @RBbodht=@LBbodht\relax% \fi \ifdim@LBtopht<@RBtopht\relax% @pokeabove=@RBtopht% \else @pokeabove=@LBtopht% \fi \ifdim@LBbotdp<@RBbotdp\relax% @pokebelow=@RBbotdp% \else @pokebelow=@LBbotdp \fi \topsep=0pt \partopsep=0pt \begin{trivlist} \item\rule{0pt}{@pokeabove}\smash{\begin{minipage}[t][\dimexpr@LBbodht+@LBtopht+@LBbotdp\relax]{@LBwd} \setlist{itemsep=\fill}% @leftbodycontent% \end{minipage}}\hfill\smash{\begin{minipage}[t][\dimexpr@RBbodht+@RBtopht+@RBbotdp\relax]{@RBwd} \setlist{itemsep=\fill}% @rightbodycontent% \end{minipage}}\vskip\dimexpr@RBbodht-\baselineskip\relax \item \rule[-@pokebelow]{0pt}{@pokebelow} \end{trivlist} } \makeatother

\begin{document}

\lipsum[2] \begin{unevencols}{0.6\textwidth}{0.4\textwidth} \begin{leftbody} \begin{description} \item \lipsum[1][1] \item \lipsum[1][2] \item \lipsum[1][3] \item \lipsum[1][4] \end{description} \end{leftbody}% \begin{rightbody} \begin{description} \item \lipsum[1][5-6] \item \lipsum[1][7-9] \end{description} \end{rightbody} \end{unevencols} \lipsum[3] \begin{unevencols}{0.59\textwidth}{0.2\textwidth} \begin{leftbody} \begin{description} \item \lipsum[1][1] \item \lipsum[1][2] \item \lipsum[1][3] \item \lipsum[1][4] \end{description} \end{leftbody}% \begin{rightbody} \begin{description} \item aaa \item aaa \end{description} \end{rightbody} \end{unevencols} \lipsum[4]

\end{document}

In the image below you see that now even when the text in one of the boxes have no ascenders or descenders, the baseline alignment is still correct. Note that by using the measured top-line-height and bottom-line-depth, the spacing will still be correct if you have material that exceeds the "normal" height/depth of a line (e.g. when you have math material or super/subscripts). Without this computation, things may overprint.

enter image description here

Note also that this solution aligns the baselines of the top and bottom lines of the material in the two boxes. If one of the boxes have extra tall or extra deep material, the visual alignment may be poorer. Here I show what happens with some outrageous math.

enter image description here

Willie Wong
  • 24,733
  • 8
  • 74
  • 106