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?

7
  • 1
    Welcome! You don't care if the baselines of the texts are aligned except for the first and last lines?
    – cfr
    Dec 12, 2023 at 1:20
  • @cfr yes, that's right. Dec 12, 2023 at 1:25
  • That's very poor typography ....
    – cfr
    Dec 12, 2023 at 1:30
  • For my use case, the height difference between columns is more annoying. And I can't have both right? Dec 12, 2023 at 1: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, 2023 at 1:45

2 Answers 2

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

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}
5
  • 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. Dec 12, 2023 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 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.) Dec 13, 2023 at 4: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? Dec 13, 2023 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 tex.stackexchange.com/questions/349178/… Dec 13, 2023 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. Dec 14, 2023 at 3:31

You must log in to answer this question.

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