[Tex/LaTex] Uneven spacing around blockquote

spacing

For my dissertation, which I am in the final stages of formatting, I am required to use double-spacing for the main text and single-spacing for blockquotes. But this has somehow produced the annoying result that the space before and the space after a blockquote are not the same size. Oh LaTeX experts, help me fix it!

Example code:

\documentclass[11pt,oneside]{book}
\usepackage[letterpaper]{geometry}

\usepackage{setspace}

\expandafter\def\expandafter\quote\expandafter{\quote\singlespacing}
\expandafter\def\expandafter\quotation\expandafter{\quotation\singlespacing}

\doublespacing
\parskip=0pt

\usepackage{lipsum}

\begin{document}
\lipsum[1]
\begin{quotation}Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.  \end{quotation}
\lipsum[1]
\end{document}

Example image:

Example

Related: How can I change the indentation in quote and quotation environments and commands?

Best Answer

Warning: long answer ahead!

The setspace package has a long history that dates back (perhaps with a different name, I don’t remember) to the late Eighties of the past century, to the ancient days of LaTeX 2.09 and TeX2; the comments at the beginning of setspace.sty witness to this, as well as to a long and not always linear incremental development, during which provisional solutions were being added to solve problems and bugs as they were reported. The comments also warn you that, even in the latest release (my version, distributed with TeX Live 2015, is copyrighted 2011), some issues may remain unresolved; in particular, lines 284–285 read

\begin{singlespace}\begin{quote} produces the wrong spacing before the quote (extra glue is inserted).

Indeed, the anomalous behavior complained about in the question comes, IMHO, out of a tiny bug in the \singlespacing command; I will try to analyze it in detail in this answer, and to propose a correction.


Detailed analysis

Quoting again from the comments of setspace.sty, lines 54–58:

The extra \vskip in the definition of \singlespacing seems to make for a cleaner transition from multiple spacing back to single spacing. These did not appear warrranted [sic] for other size changes.

What is this about? Well, multiple spacing is achieved, obviously, by incrementing the leading between the lines, that is (Oxford Dictionary of English, as presented by the Dictionary application of Mac OS X), “the distance from the bottom of one line of type to the bottom of the next”. Now, (La)TeX applies the same leading not only to all lines of a given paragraph, but also between the first line of that paragraph and the last line of the previous one. This means that, when two successive paragraphs are typeset with different leadings, the leading between the last line of the first and the first line of the second will always be the same as the leading between the lines of the second paragraph. When you change from a smaller leading to a larger one, this looks right, but it does not the other way around (just think of it): in the latter case, it rather seems that the larger leading should be used between the two paragraphs too.

In an attempt to make up for this, the \singlespacing command adds an extra blank line, that has the new (single-line) leading both above and below itself:

\newcommand{\singlespacing}{%
  \setstretch {\setspace@singlespace}%  normally 1
  \vskip \baselineskip  % Correction for coming into singlespace
}

But this would yield the desired effect only if the “old” leading were exactly twice as tall as the “new” one; so:

  • it evidently does not work when changing from \onehalfspacing to \singlespacing, as it is perhaps hinted at by the comment on lines 54–58;

  • it doesn’t work even when changing from \doublespacing to \singlespacing, because the leading of the former style is not at all twice as much as the leading of the latter.

Indeed, what is normally considered “double spacing” is a spacing in which the baselines of text are separated by an amount of vertical space that is twice as much as the font size; for example, for a font size of 11 points, as it is in the question, the baselines should be 22 points apart. But the leading in \singlespacing conditions is already set to 120%—125% of the font size, e.g., to 13.6 points for a size of 11 points: setting the leading to twice as much would result in a leading of 27.2 point, that is, in almost “two-lines-and-a-half spacing”. For this reason, the setspace package implements \doublespace by setting the multiplication factor for the leading to values actually smaller than two:

\newcommand{\doublespacing}{%
  \setstretch {1.667}%  default
  \ifcase \@ptsize \relax % 10pt
    \setstretch {1.667}%
  \or % 11pt
    \setstretch {1.618}%
  \or % 12pt
    \setstretch {1.655}%
  \fi
}

As you see, for 11pt a multiplier of 1.618 is used (reminiscent of the golden ratio?), yielding an effective leading of 1.618 * 13.6pt = 22,0048pt, that is, almost exactly the double of the font size, as intended. In conclusion, the \vskip \baselineskip issued by the \singlespacing command turns out to be overcompensation, and this is precisely the source of the extra space that has been asked about.

We can easily confirm this by compiling a slightly modified version of the OP’s MWE:

\documentclass[11pt,oneside]{book}
\usepackage[letterpaper]{geometry}

\usepackage{setspace}

\expandafter\def\expandafter\quote\expandafter{\quote\singlespacing}
\expandafter\def\expandafter\quotation\expandafter{\quotation\singlespacing}

\doublespacing
\parskip=0pt

\usepackage{lipsum}

\begin{document}
\lipsum[1]
\begin{quotation}
    Curabitur dictum gravida mauris.  Nam arcu libero, nonummy eget,
    consectetuer id, vulputate a, magna.  Donec vehicula augue eu neque.
    Pellentesque habitant morbi tristique senectus et netus et malesuada fames
    ac turpis egestas.
\end{quotation}
\lipsum[2]

\singlespacing

\lipsum[3]

\showboxbreadth = 1000
\showboxdepth = 10
\showlists

\end{document}

This code produces the following output:

Printout with the wrong spacing

The tracing commands included near the end of the code write into the transcript file (among other things) detailed information about the space that goes between the lines. The beginning of this diagnostic tracing reads as follows:

### vertical mode entered at line 0
### current page:
\write-{}
\glue(\topskip) 3.39584
\hbox(7.60416+2.12917)x430.00462, glue set - 0.16643
.\hbox(0.0+0.0)x17.0
.\OT1/cmr/m/n/10.95 L
.\OT1/cmr/m/n/10.95 o
.\OT1/cmr/m/n/10.95 r
.\OT1/cmr/m/n/10.95 e
.\OT1/cmr/m/n/10.95 m
.\glue 3.65 plus 1.825 minus 1.21666

…96 lines omitted…

.\glue(\rightskip) 0.0
\penalty 150
\glue(\baselineskip) 12.27142
\hbox(7.60416+2.12917)x430.00462, glue set 0.52057
.\OT1/cmr/m/n/10.95 p
.\OT1/cmr/m/n/10.95 l
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 c

The \hbox that begins on the fifth line is the first typeset line of the first paragraph, which ends with .\glue(\rightskip) 0.0 about a hundred lines below; we can see that the depth of this line is 2.12917 (points). A \penalty 150 follows, coming from \clubpenalty, and then an “interline glue” of 12.27142 points (\glue(\baselineskip) 12.27142), which is precisely the vertical space that TeX inserts between two typeset lines to ensure that their respective baseline are as much apart as desired. Since the next typeset line, that begins with \hbox(7.60416+2.12917)x430.00462..., has a height of 7.60416 points, we see that TeX is assuming a leading of 2.12917 + 12.27142 + 7.60416 = 22,00475 points, as claimed above (within rounding errors.

Let‘s now have a look to the excerpt that corresponds to the beginning of the quotation environment:

\hbox(7.60416+2.12917)x430.00462, glue set 115.40472fil
.\OT1/cmr/m/n/10.95 s
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 g
.\OT1/cmr/m/n/10.95 i
.\OT1/cmr/m/n/10.95 t

…60 lines omitted…

.\glue 3.65 plus 1.825 minus 1.21666
.\OT1/cmr/m/n/10.95 r
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 t
.\OT1/cmr/m/n/10.95 r
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 m
.\OT1/cmr/m/n/10.95 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\penalty -51
\glue 12.0 plus 4.0 minus 6.0
\glue 13.6
\glue(\parskip) 0.0 plus 1.0
\glue(\baselineskip) 3.86668
\hbox(7.60416+2.12917)x375.2545, glue set 0.4625, shifted 27.37506

The \hbox whose contents begin with the five characters “s-a-g-i-t” and ends with “r-u-t-r-u-m” + other stuff + .\glue(\rightskip) 0.0 is the last typeset line of the first paragraph, immediately above the quotation; we report this line too, because we need to know that its depth is (again) 2.12917 points. After this box we find:

  • \penalty -51 (bonus for breaking the page before the quotation);

  • \glue 12.0 plus 4.0 minus 6.0 (vertical space inserted above quotations);

  • \glue 13.6, which is the (over-)compensation inserted by the \singlespacing command for the change in the spacing;

  • \glue(\parskip) 0.0 plus 1.0 (vertical space inserted between paragraphs);

  • \glue(\baselineskip) 3.86668 (see below);

  • \hbox(7.60416+2.12917)x375.2545..., which is the beginning of the box that contains the first typeset line of the quotation; note that its height is 7.60416 (points).

If we add to this height the depth of the previous line and the interline glue, we can check that the latter has been computed to attain a leading of 7.60416 + 2.12917 + 3.86668 = 13.60001 (always points), that is, within rounding errors, the “normal” (for an 11-point font) leading of 13.6 points. The overall distance between the baseline of the last line of the preceding paragraph and that of the first line of the quotation is 13.60001 + 13.6 + 12.0 ≈ 39.2 points (omitting stretch and shrink components); but it had better been 22.0048 + 12.0 ≈ 34.0 points, that is [“double-spacing” leading] + [space above quotation]. Note that the difference amounts to about 1.83mm, that is, enough to be clearly perceived.

To confirm that the distance should have been as much as just claimed, consider the transcript of what happens at the end of the quotation environment:

\hbox(7.60416+2.12917)x375.2545, glue set - 0.66791, shifted 27.37506
.\OT1/cmr/m/n/10.95 h
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 b
.\OT1/cmr/m/n/10.95 i

…85 lines omitted…

.\OT1/cmr/m/n/10.95 t
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 s
.\OT1/cmr/m/n/10.95 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\penalty -51
\glue 12.0 plus 4.0 minus 6.0
\glue(\parskip) 0.0
\glue(\baselineskip) 12.27142
\hbox(7.60416+2.12917)x430.00462, glue set - 0.10161
.\OT1/cmr/m/n/10.95 N
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 m
.\glue 3.65 plus 1.825 minus 1.21666
.\OT1/cmr/m/n/10.95 d
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 i
.\glue 3.65 plus 1.825 minus 1.21666
.\OT1/cmr/m/n/10.95 l
.\OT1/cmr/m/n/10.95 i
.\OT1/cmr/m/n/10.95 g
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 l
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 ,

Once again, the transcript starts with the beginning of the last line of the quotation (“h-a-b-i-…”), so that you can see that its depth is (once again) 2.12917 points, and finishes reporting the beginning of the first line of the paragraph that follows the quotation (“N-a-m [space] d-u-i [space] l-i-g-u-l-a [comma]…”, whose height is (this too) 7.60416 points. Analyzing this transcript along the lines given above, we can check that the \glue(\baselineskip) 12.27142 has been calculated for a leading of 2.12917 + 12.27142 + 7.60416 = 22,00475 points, exactly as between any two lines of a paragraph typeset while \doublespacing is in force (see above). Thus, the total distance between the baseline of the last line of the quotation and that of the first line of the ensuing paragraph is 22.00475 + 12.0 ≈ 34.0 points (instead of the 39.2 points that we found above the quotation).

You can similarly check that there is the same amount of excess space (overcompensation) before the last paragraph, where just a switch from \doublespacing to \singlespacing occurs, without the complication of a quotation environment being entered. The interline glue inserted before the first line of the last paragraph gives rise to a leading of 13.00001 points, and there is, an addition, the usual (buggy) vertical space of 13.6 points; once again, the total is (approximately) 27.2 points, instead of 22.0048, as it should be to replicate the leading between the two last lines of the preceding paragraph. Anyway, this excess space is clearly visible in the printout.


Proposed correction

The correction we propose is a patch to the \singlespacing command; after that, the usual quote and quotation environment can be employed, giving the correct result. In the following code, this patch to \singlespacing is exactly the segment delimited by \makeatletter and \makeatother.

\documentclass[11pt,oneside]{book}
\usepackage[letterpaper]{geometry}
\usepackage{setspace}
\usepackage{lipsum}

\makeatletter

\renewcommand*\singlespacing{%
    \par    % ensure vertical mode
    \null   % add fake line with previous leading still in force
    \setstretch {\setspace@singlespace}% change leading
    \nobreak
    \vskip -\baselineskip   % compensate for the fake line we added, but with 
                            % the new leading
    \vskip \z@skip  % tell "\addvspace" and "\addpenalty" _not_ to remove the 
                    % above correction
}

\makeatother

% I’d go for different names, anyway; or follow advice given in other answers to
% patch up the standard environments.
\newenvironment*{JoeMquote}{%
    \singlespacing
    \quote
}{\endquote}
\newenvironment*{JoeMquotation}{%
    \singlespacing
    \quotation
}{\endquotation}

\doublespacing
\setlength{\parskip}{0pt}



\begin{document}
\lipsum[1]
\begin{JoeMquotation}
    Curabitur dictum gravida mauris.  Nam arcu libero, nonummy eget,
    consectetuer id, vulputate a, magna.  Donec vehicula augue eu neque.
    Pellentesque habitant morbi tristique senectus et netus et malesuada fames
    ac turpis egestas.
\end{JoeMquotation}
\lipsum[2]

\singlespacing

\lipsum[3]

\showboxbreadth = 1000
\showboxdepth = 10
\showlists

\end{document}

Note that we prefer to define two new environments, rather than changing the default ones. Indeed, this answer is about finding the exact compensation that yields the same vertical space above and below the quotation, not about how to incorporate this correction into the standard environments: the other answers have already taken care of explaining this.

The printout that this code produces is shown next: you can immediately check, at first sight, that this time the spacing looks correct.

Printout with the correct spacing

The tracing written to the transcript file confirms that the spacing is indeed correct to the scaled point. This is the beginning of the quotation environment, including the last line above it:

\hbox(7.60416+2.12917)x430.00462, glue set 115.40472fil
.\OT1/cmr/m/n/10.95 s
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 g
.\OT1/cmr/m/n/10.95 i
.\OT1/cmr/m/n/10.95 t

…60 lines omitted…

.\glue 3.65 plus 1.825 minus 1.21666
.\OT1/cmr/m/n/10.95 r
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 t
.\OT1/cmr/m/n/10.95 r
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 m
.\OT1/cmr/m/n/10.95 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\glue(\baselineskip) 19.87558
\hbox(0.0+0.0)x0.0
\penalty 10000
\glue -13.6
\glue 0.0
\penalty -51
\glue 12.0 plus 4.0 minus 6.0
\glue(\parskip) 0.0 plus 1.0
\glue(\baselineskip) 5.99585
\hbox(7.60416+2.12917)x375.2545, glue set 0.4625, shifted 27.37506

The distance between the baseline of the last line of the preceding paragraph and the baseline of the first line of the quotation is 2.12917 + 19.87558 - 13.6 + 12.0 + 5.99585 + 7.60416 = 34.00476, which corresponds exactly, within rounding errors, to the expected value of [“double-spacing” leading] + [space above quotation] = 22.00475 + 12.0 = 34.00475. On the other hand, at the end of the quotation we find

\hbox(7.60416+2.12917)x375.2545, glue set - 0.66791, shifted 27.37506
.\OT1/cmr/m/n/10.95 h
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 b
.\OT1/cmr/m/n/10.95 i

…85 lines omitted…

.\OT1/cmr/m/n/10.95 t
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 s
.\OT1/cmr/m/n/10.95 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\penalty -51
\glue 12.0 plus 4.0 minus 6.0
\glue(\parskip) 0.0
\glue(\baselineskip) 12.27142
\hbox(7.60416+2.12917)x430.00462, glue set - 0.10161

(as usual, the beginning of the first line of the following paragraph is shown too). Here the distance between the two baselines is 2.12917 + 12.0 + 7.60416 + 12.27142 = 34.00475, exactly the same (as always, within rounding errors to the scaled point) as above the quotation.

The same (but without the \glue 12.0 plus 4.0 minus 6.0) happens at the \singlespacing change before the last paragraph, as you can check by yourself:

\hbox(7.31305+0.0)x430.00462, glue set 394.62999fil
.\OT1/cmr/m/n/10.95 m
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 r
.\OT1/cmr/m/n/10.95 i
.\OT1/cmr/m/n/10.95 s
.\OT1/cmr/m/n/10.95 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\glue(\baselineskip) 22.00475
\hbox(0.0+0.0)x0.0
\penalty 10000
\glue -13.6
\glue 0.0
\glue(\parskip) 0.0
\glue(\baselineskip) 5.99585
\hbox(7.60416+2.12917)x430.00462, glue set 0.28633
.\hbox(0.0+0.0)x17.0
.\OT1/cmr/m/n/10.95 N
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 l
.\OT1/cmr/m/n/10.95 l
.\OT1/cmr/m/n/10.95 a
.\glue 3.65 plus 1.825 minus 1.21666
.\OT1/cmr/m/n/10.95 m
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 l
.\OT1/cmr/m/n/10.95 e
.\OT1/cmr/m/n/10.95 s
.\OT1/cmr/m/n/10.95 u
.\OT1/cmr/m/n/10.95 a
.\OT1/cmr/m/n/10.95 d
.\OT1/cmr/m/n/10.95 a
.\glue 3.65 plus 1.825 minus 1.21666

A final remark: the correction should, and can, be implemented at a more general level, encompassing all possible cases of change of spacing. Rather that appending stray boxes and glue to the vertical list, a general algorithm should simply compute the difference between the old leading and the new one (the old minus the new) and, if this difference is positive, add a vertical space of exactly that amount.