Vertical space after minipages
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
\showboxbreadth=10000
\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 \hbox
es 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:
- The second
\vbox
corresponds to our\vtop
; - A
\parskip
was inserted between paragraphs; and - No
\baselineskip
was inserted between the\vtop
and the following\hbox
which containsNext 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.
- This doesn't work with
minipage
, I didn't investigate why. -
enumerate
will add space above it normally. This is inhibited byminipage
which executes\@setminipage
. I understand how\@setminipage
works, but I don't understand how to prevent this behavior just usingenumitem
'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
\advance\skip0 by-\prevdepth
\advance\skip0 by-\ht\strutbox\relax
\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}
Gotti91
Updated on June 29, 2020Comments
-
Gotti91 over 3 years
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}
-
cfr over 6 yearsPut them inside another minipage and set that with
b
, possibly. -
David Carlisle over 6 years@cfr that wouldn't work
-
cfr over 6 yearsPossibly not, then. @DavidCarlisle
-