# Changes in spacing (“Spacing” environment) for a block should not affect the line spacing of the block to the material above and below

When I use memoir with \OnehalfSpacing and I temporarily set things within \begin{Spacing}{1}[...]\end{Spacing} (\SingleSpacing for some reason leads to looser spacing elsewhere in my document), I get uneven line spacing:

\documentclass{memoir}
\usepackage{lipsum}

\OnehalfSpacing
\raggedbottom

\begin{document}

\lipsum[1] Before the block \dots
\par\nopagebreak\vspace{0.25\baselineskip}\nopagebreak % not sure whether two occurrences of \nopagebreak are needed
\begin{Spacing}{1}
\begin{tabular}{ll}
foo & bar \\
baz & qux \\
\end{tabular}
\end{Spacing}
\par\vspace{0.5\baselineskip}
\noindent \ldots{} after the block.

\lipsum[1] Before the block \ldots
\par\nopagebreak\vspace{0.25\baselineskip}\nopagebreak % not sure whether two occurrences of \nopagebreak are needed
\begin{Spacing}{1}
\noindent
\hspace*{1cm} foo \\
\hspace*{1cm} bar \\
\hspace*{1cm} baz
\end{Spacing}
\par\vspace{0.2\baselineskip}
\noindent \ldots{} after the block.

\newpage

\lipsum[1] Before the block \dots
\begin{Spacing}{1}
\begin{tabular}{ll}
foo & bar \\
baz & qux \\
\end{tabular}
\end{Spacing}
\noindent \ldots{} after the block.

\lipsum[1] Before the block \ldots
\begin{Spacing}{1}
\noindent
\hspace*{1cm} foo \\
\hspace*{1cm} bar \\
\hspace*{1cm} baz
\end{Spacing}
\noindent \ldots{} after the block.

\end{document}


Page 1 uses \vspace commands with manually set arguments to correct for the uneven spacing (my values are visual guesses). Page 2 has the same content but shows the result if those 4 lines are omitted; this is what I mean by "uneven". My usage of \par is inspired by this question about the same issue on the paragraph level; it might not be necessary.

What I want is line spacing that is evenly 1.5-spaced up to the first line of the 1-spaced content and that is evenly 1.5-spaced starting with the last line of the 1-spaced content. That is, the spacing between the "foo"-line and the line above (in both instances) and between the "baz"-line and the line below (in both instances) should show ordinary 1.5-spacing, like the "lorem ipsum" paragraphs. Is there an easy way to achieve such even spacing? Note my use of \raggedbottom. There should be no distinction whether the embedded material "belongs to the previous paragraph" or not. ("LaTeX goes to a lot of effort to distinguish in-paragraph lists from end- or start-of-paragraph lists"; comment (quoted approximately) by David Carlisle)

-

The following does what is wanted, for tabulars. It uses the fact that tabular line spacing is determined by \strutbox whose height and depth in the memoir class are defined to be respectively .7 and .3 of the current \baselineskip.

Actually, this is the same as in the article class. Anyhow using \strutbox in the code is better, so I updated accordingly the answer. And the code now also takes into account \arraystretch (changes to \arraystretch should happen before the \MySpacing environment).

The included output has examples on two columns.

Last edit: new version of the helper macro \AfterMySpacing, which deals better with a page break occuring exactly after the end of the \MySpacing environment.

Added explanations: this document (with memoir class) starts in \OnehalfSpacing mode (this is a macro of memoir which enlarges the \baselineskip by a value depending on the type size, for 10pt the factor is 1.25). Then the column on the right switches to \DoubleSpacing (this does not mean that the interline spacing is doubled, the ratio is rather 1.667 for 10pt size).

The boxed values are the parameters given to the \MySpacing environment. This parameter tells the environment which multiple of the standard baselineskip (whose value is set up by the class depending on the font size option passed to it) to use for interline spacing in the tabular environment (recall that tabulars add \struts to ensure regular line spacing -- a safeguard which fails if a cell contents has a height or depth larger than the used strut). This multiplier is applied to the default \baselineskip, not to the one used in the surrounding paragraph already stretched out either by \OnehalfSpacing or \DoubleSpacing.

Finally, there is a LaTeX parameter called \arraystretch, normally set to 1, which multiplies the interline-spacing of all tabulars and arrays. The environment \MySpacing was written to take it into account. So the examples end with a test of this by setting the \arraystretch to 2 but using parameter .5 so that the net effect is like using \MySpacing with parameter 1.

Note 1: with the parameter given to \MySpacing set to only .75, the strut used in the tabular has (with the default fonts) its height a tiny bit smaller than the height of the letter X (circa half a point smaller), hence the line spacing is not exactly as intended (and can be irregular inside the tabular, depending on its content), although this is not so visible to the naked eye. But this problem goes away for parameter values higher than .82.

Note 2: if the environment \MySpacing contains, rather than a tabular, text in lines (ending with \\ except the last one), the wished-for spacing with respect to the surrounding lines will be obtained by inserting a \strut in both the first and the last lines of the enclosed block. (assuming \arraystretch equal to 1).

\documentclass{memoir}
\usepackage{multicol}

\OnehalfSpacing
\raggedbottom

\makeatletter

% helper macro for the environment MySpacing
% initial version:
%\newcommand{\AfterMySpacing}{\noindent
%       \vphantom{\vrule height \baselineskip depth \z@}}

% new method, better if pagebreak occurs right after the MySpacing block
\newcommand{\AfterMySpacing}{%
\vskip\dp\strutbox
\prevdepth\dp\strutbox
\noindent\strut}  % <- the  \strut here could be removed, TeX adds the
% necessary vertical skip.
% And, actually, perhaps the macro would be more flexible
% also with the ending \noindent removed.

\newenvironment{MySpacing}[1]
{\par\nointerlineskip
\vskip\baselineskip
\def\baselinestretch{#1}\@currsize
\vskip-\arraystretch\ht\strutbox\relax % replaces \vskip-.7\baselineskip
}
{\par\nointerlineskip
\vskip-\arraystretch\dp\strutbox\relax  % replaces \vskip-.3\baselineskip
\ignorespacesafterend\aftergroup\AfterMySpacing}
\makeatother

\begin{document}

\begin{multicols}{2}
\fbox{2} Before the block Before the block Before the block\dots
\begin{MySpacing}{2}
\hspace*{1cm}%
\begin{tabular}{ll}
ooo & xxx \\
baz & qux \\
foo & pqr \\
\end{tabular}
\end{MySpacing}
\ldots{} after the block after the block after the block after the block
after the block

\fbox{1} Before the block Before the block Before the block\dots
\begin{MySpacing}{1}
\hspace*{1cm}%
\begin{tabular}{ll}
ooo & XXX \\
baz & qux \\
foo & abc \\
\end{tabular}
\end{MySpacing}
\ldots{} after the block after the block after the block after the block
after the block

\fbox{.75} Before the block Before the block Before the block\dots
\begin{MySpacing}{.75}
\hspace*{1cm}%
\begin{tabular}{ll}
ooo & XXX \\
baz & qux \\
foo & pqr \\
\end{tabular}
\end{MySpacing}
\ldots{} after the block after the block after the block after the block
after the block

\columnbreak

\DoubleSpacing

\verb|\DoubleSpacing|

\fbox{2} Before the block Before the block Before the block\dots
\begin{MySpacing}{2}
\hspace*{1cm}%
\begin{tabular}{ll}
ooo & XXX \\
baz & qux \\
foo & pqr \\
\end{tabular}
\end{MySpacing}
\ldots{} after the block after the block after the block after the block
after the block

\renewcommand{\arraystretch}{2}

\verb|\renewcommand{\arraystretch}{2}|
% for testing purposes

\fbox{.5} Before the block Before the block Before the block\dots
\begin{MySpacing}{.5}
\hspace*{1cm}%
\begin{tabular}{ll}
ooo & XXX \\
baz & qux \\
foo & pqr \\
\end{tabular}
\end{MySpacing}
\ldots{} after the block after the block after the block after the block
after the block

\end{multicols}

\end{document}


-
This works; well-researched! –  Lover of Structure Feb 27 '13 at 17:50

The problem is actually unrelated to the Spacing environment. If you use a table mid document then by default it is centred, so it has large depth and TeX has no knowledge of the baseline of the last row of the table. So for the following material it gives up on baseline alignment and uses \lineskip glue instead.

If by hand you tell TeX to act as if the thing just typeset had the depth of a q rather than the depth it actually has (half the total vertical height of the table) then TeX aligns to that. The Spacing environment already seems to be doing the correct thing with adjusting for the difference between the baselines implied by that environment.

\lipsum[1] Before the block \dots
\begin{Spacing}{1}
\begin{tabular}{ll}
foo & bar \\
baz & qux \\
\end{tabular}
\par
\setbox0\hbox{q}
\prevdepth\dp0
\end{Spacing}
\noindent \ldots{} 000after the block.


That fixes the bottom, so you could use a \begin{tabular}[t] so the table baseline is on its top row, then the top would be automatically right.

You could of course patch tabular to save and restore the \prevdepth automatically, but you probably wouldn't want to make that a global change.

Also you would get the same with any other large display, graphics, minipage etc so just patching tabular wouldn't really be a solution.

So I suspect hand correction will always be required (but by setting \prevdepth you get the exact value required, you don't have to guess visually).

This is one of the motivating use cases for LaTeX3 coffins, which allow you to access multiple handles and in particular the baseline of both top and bottom row, however in this case it's not a lot of use unless the entire vertical list is being assembled in a coffin-aware way, and for that you need xgalley and probably xor, which aren't really ready yet.

-
Perhaps my hand-tuned \vspace-values were not optimal. What I meant was that the "Before the block" and "after the block" text should have the same distance to the line below as to the line above (in both cases). If you replace \OnehalfSpacing by \DoubleSpacing and apply your suggested fix (namely: [t]-placement and \fixbottomspacing (with the definition \newcommand*{\fixbottomspacing}{\par \setbox0\hbox{q} \prevdepth\dp0})) to the material on page 2, one can see that the result is not yet what I desire. –  Lover of Structure Feb 21 '13 at 14:46
yes sorry, got busy, I can confirm what you say that the Spacing environment isn't getting it quite right. setting prevdepth as in the answer means it has the information so it could get it right but it means I'd have to look exactly what the package is doing, perhaps over the weekend –  David Carlisle Feb 23 '13 at 0:45