Vertical space after minipages

I would like to integrate two minipages inside a text, keeping the line spacing. Using the \begin{minipage}[t] option, the space above the minipages is correct (green circle). But unfortunately, the space below is far too short (red circle). How can I adjust it to the "normal baselineskip"?

MWE:

\documentclass[a4paper,DIV=15,oneside,12pt]{scrartcl}
\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{blindtext}
\usepackage{setspace}
\usepackage{enumitem}

\parskip 0pt
\parindent 0pt

\begin{document}
\pagestyle{empty}
\onehalfspacing

\blindtext\par
\begin{minipage}[t]{0.6\textwidth}
\blindtext
\end{minipage}\hfill
%Minipage 2
\begin{minipage}[t]{0.37\textwidth}
%\centering\rule{3cm}{2cm}
\begin{enumerate}[leftmargin=*,label=\alph{*}),itemsep=0pt,partopsep=0pt,topsep=0pt, parsep=0pt]
\item Test 1
\item Test 2
\end{enumerate}
\end{minipage}\par
\blindtext
\end{document}

• Put them inside another minipage and set that with b, possibly.
– cfr
Jun 29 '17 at 0:54
• @cfr that wouldn't work Jun 29 '17 at 6:34
• Possibly not, then. @DavidCarlisle
– cfr
Jun 29 '17 at 22:24

The explanation for your problem is quite complex. If you'd like, you can just skip down to the solution below.

Explanation

When TeX is typesetting paragraphs, it behaves roughly as follows: It first breaks the paragraph into lines (using a complex algorithm with a number of parameters). These lines placed into a horizontal box (or \hbox) and the boxes are placed on the main vertical list. The main vertical list holds all of the material from which pages are created.

TeX tries to make sure that successive horizontal boxes on the vertical list are spaced such that the baselines of each box are \baselineskip apart. We can use TeX to see this in action.

Here's some plain TeX (compile with tex or pdftex)

\showboxdepth=1
\tracingonline=1

\setbox0=\vbox{
First line\hfil\break
Second line
}
\showbox0
\end


When compiled, it prints out the contents of the \vbox inside which the paragraph has been broken into two lines. The \boxshow... parameters control how TeX prints the contents of the box. Here's the output.

> \box0=
\vbox(18.94444+0.0)x469.75499
.\hbox(6.94444+0.0)x469.75499, glue set 409.81047fil []
.\penalty 300
.\glue(\baselineskip) 5.05556
.\hbox(6.94444+0.0)x469.75499, glue set 420.31046fil []


This can be a little complicated to read at first, but what it's telling us is that \box0 is a \vbox that is 18.94444pt in height, 0pt in depth and 469.75499pt wide. That is, (height+depth)xwidth. Inside that we can see the two \hboxes corresponding to the two lines of the paragraph. Between them, there's a \glue that corresponds to \baselineskip. Note that the depth of the top box plus the glue plus the height of the bottom box is 12pt which is \baselineskip.

Now TeX also doesn't want successive boxes to get to close together to prevent them from overlapping. To prevent this, TeX will insert some space between the boxes when they are too close together. The exact algorithm is unimportant here, but the key is that we can disable this behavior by using \nointerlineskip.

Now you might be wondering how two boxes of text could ever be too close together. This can happen if you have a box with depth m on top of a box with height n such that m + n > \baselineskip.

So what does all of this have to do with your question? Well, TeX has three types of vertical boxes, \vbox, \vtop, and \vcenter. Let's ignore \vcenter since it's a bit strange. \vbox and \vtop differ in where they place their reference point—that is the point that corresponds to their baseline. A \vbox sets its reference point to be the reference point of the last box in the list (i.e., usually the baseline of the last line of the paragraph in the box). In contrast, a \vtop sets its reference point to be the reference point of the first box in the list (i.e., the baseline of the top line in the paragraph).

We can see this in action.

\noindent
\vbox{
\hsize=1in
Top line\hfill\break
Bottom line
}
\vtop{
\hsize=1in
Top line\hfill\break
Bottom line
}
\end


You can see how the bottom line of the left box is aligned with the top line of the right box.

We can print what these two boxes look like as we did before.

The left box:

\vbox(18.94444+0.0)x72.26999
.\hbox(6.94444+1.94444)x72.26999, glue set 16.4366fill []
.\penalty 300
.\glue(\baselineskip) 3.11111
.\hbox(6.94444+0.0)x72.26999, glue set 20.18652fil []


The right box:

\vbox(6.94444+12.0)x72.26999
.\hbox(6.94444+1.94444)x72.26999, glue set 16.4366fill []
.\penalty 300
.\glue(\baselineskip) 3.11111
.\hbox(6.94444+0.0)x72.26999, glue set 20.18652fil []


The key difference is in the height and depth of these two boxes (the top line of each listing).

This leads to a tricky problem. What happens if we use a \vtop and the next line on the page is just a normal line from a paragraph? Let's take a look.

\parindent=0pt
\leavevmode
\vtop{
\hsize=1in
Top line\hfill\break
g Bottom line
}

Next line
\end


I suppressed indentation and started the second line with a g because it descends below the baseline. Let's look at the boxes that get constructed. (I wrapped everything in a \vbox and used \showbox to see the output. Thus, there is an extra outer vbox below. I increased \showboxdepth by 1 to see the next inner box.)

\vbox(28.83333+0.0)x469.75499
.\vbox(6.94444+13.94444)x72.26999
..\hbox(6.94444+1.94444)x72.26999, glue set 36.4366fill []
..\penalty 300
..\glue(\baselineskip) 3.11111
..\hbox(6.94444+1.94444)x72.26999, glue set 11.85318fil []
.\glue(\parskip) 0.0 plus 1.0
.\glue(\lineskip) 1.0
.\hbox(6.94444+0.0)x469.75499, glue set 429.75491fil
..\hbox(0.0+0.0)x0.0
..\tenrm N
..\tenrm e
..\tenrm x
..\tenrm t
..\glue 3.33333 plus 1.66666 minus 1.11111
..\tenrm l
..\tenrm i
..\tenrm n
..\tenrm e
..\penalty 10000
..\glue(\parfillskip) 0.0 plus 1.0fil
..\glue(\rightskip) 0.0


There are several pieces of note here:

1. The second \vbox corresponds to our \vtop;
2. A \parskip was inserted between paragraphs; and
3. No \baselineskip was inserted between the \vtop and the following \hbox which contains Next line. Instead there is a \lineskip. The \lineskip comes from the fact that the depth of the \vtop and the height of the following \hbox are greater than \baselineskip. If TeX had tried to make their baselines \baselineskip apart, they would overlap.

Maybe now you can see the issue with your own code. The minipage with the [t] option produces a \vtop. Thus TeX isn't ensuring that the baseline of the bottom line in the minipage is \baselineskip away from the baseline of the following line. Instead, it's inserting \lineskip which isn't nearly enough space.

You might be thinking that the solution is to switch the minipage to [b], but then you'll have an analogous situation with the line above.

Solution

The normal method for dealing with this is to put a \strut in the last line in the \vtop, turn off interline skip (i.e., inhibit the \lineskip glue), and put a \strut in the first line of the next paragraph.

A \strut inserts a box (namely \box\strutbox) which has height + depth which is usually equal to \baselineskip. However, this isn't going to work in your case. The reason is \onehalfspacing changes the \baselineskip but doesn't touch \box\strutbox.

So what we need to do is end the longer box with a \vskip of the appropriate length, turn off interline skip, and use \strut. So what is the appropriate length? Well, we want \baselineskip = (height of \box\strutbox) + (depth of the last box in the \vbox) + (our explicit \vskip).

We can compute that by setting a temporary \skip register (I picked 0) to be \baselineskip - \ht\strutbox - \prevdepth where \prevdepth is the depth of the last box on the vertical list (so the last line of text).

Two final caveats.

1. This doesn't work with minipage, I didn't investigate why.
2. enumerate will add space above it normally. This is inhibited by minipage which executes \@setminipage. I understand how \@setminipage works, but I don't understand how to prevent this behavior just using enumitem's options. So instead, this code executes \@setminipage.

Here's the complete code.

\documentclass[a4paper,DIV=15,oneside,12pt]{scrartcl}
\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{blindtext}
\usepackage{setspace}
\usepackage{enumitem}

\parskip 0pt
\parindent 0pt

\begin{document}
\pagestyle{empty}
\onehalfspacing

\blindtext\par
\noindent
\parbox[t]{0.6\textwidth}{
\blindtext

\skip0=\baselineskip
\vskip\skip0
}\hfill
\parbox[t]{0.37\textwidth}{
\csname @setminipage\endcsname
\begin{enumerate}[leftmargin=*,label=\alph{*}),itemsep=0pt,partopsep=0pt,topsep=0pt, parsep=0pt]
\item Test 1
\item Test 2
\end{enumerate}
}
\par
\nointerlineskip
\strut\blindtext
\end{document}