2

I'm using extsizes to set a book in 9-point text, and I'm using this solution to create a separator between sections of text that's invisible unless it's the last line of a page. It works great, except when I use the command \small; then, the separator becomes visible regardless of its position on the page:

\documentclass[9pt]{book}
\usepackage{extsizes}
\usepackage{xcolor}
\usepackage{xparse}

% Create semi-invisible separator:
\makeatletter
\ExplSyntaxOn
\box_new:N \g_hide_box

\AtBeginDocument {
  \vbox_set:Nn \g_hide_box {
    \color@begingroup
    \color { white }
    \hrule width \linewidth height \baselineskip depth \c_zero_dim
    \color@endgroup
  }
}

\NewDocumentCommand \ornament { } {
  \par
  \nopagebreak
  \centerline { $ * \quad * \quad * $ }
  \vskip -0.8\baselineskip
  \cleaders \box_use:N \g_hide_box \vskip 1.1\baselineskip
  \par
}
\ExplSyntaxOff
\makeatother

\begin{document}
Blah blah blah.
\ornament

Blah blah blah.

\small
Blah blah blah.
\ornament

Blah blah blah.
\end{document}

MWE output

Any of the following makes the separator invisible again:

  • Setting the book in a font size that LaTeX supports by default (i.e., 10, 11 or 12 points)
  • Not loading extsizes
  • Not using the \small command

Anyone know a solution that allows me to keep all these settings as they are?

Edit: Increasing the \baselineskip coefficient to about 1.25 makes the problem go away, but it also makes the vertical gaps too big in both \normalsize and \small.

  • 1
    Your "hide box" has a height of 10.95pt, the cleaders should fill a vskip of 1.1\baselineskip, for small this 9.9pt and so there is not enough place for one copy of the box. – Ulrike Fischer Oct 11 at 17:31
  • How can I make it work for both sizes without increasing the amount of vertical space it creates? – skiasaurus Oct 12 at 5:58
2

Unfortunately, the nodes that contain instructions to change the current ink color are not discardable, so you need to bury them inside a \leaders box; this does not allow the use of \leaders that directly employ rules (e.g., \leaders \hrule width \linewidth \vskip ...).

However, it suffices to rebuild the box used in the \leaders each time the \ornament command is invoked, instead of packaging it once for all at the \begin{document} hook, so that it conforms to the current font size. Here is a compilable example:

\documentclass[9pt]{extbook}
\usepackage[T1]{fontenc}
\usepackage{color}

\makeatletter

\newsavebox\@hide@ornament@box
\newcommand*\ornament[1][\baselineskip]{%
    \par
    \setbox\@hide@ornament@box \vbox{%
        \kern \dp\strutbox
        \color@begingroup
            % \color{white}% for deployment
            \color{yellow}% for testing
            \hrule
                \@width  \linewidth
                \@height \baselineskip
                \@depth  \z@
        \color@endgroup
        \kern -\dp\strutbox
    }%
    \skip@ #1%
    \advance \skip@ -\baselineskip
    \divide \skip@ \tw@
    % Or:
    % \skip@ \glueexpr (#1-\baselineskip)/\tw@ \relax
    \nobreak \vskip\skip@
    \centerline{$*\quad*\quad*$}
    \nobreak \vskip\skip@
    \penalty\z@ % breakpoint; adjust penalty value as you please
    \vskip -\glueexpr \skip@+\baselineskip \relax
    \cleaders \box\@hide@ornament@box
        \vskip \baselineskip
    \vskip\skip@
    \vskip\z@skip % allow for "\addvspace"
}

% \showboxbreadth   = \@M
% \showboxdepth     = \sixt@@n
% \tracingonline    = 1

\makeatother

\newcommand*{\Text}{Blah blah blah:
    This meaningless sample text
    is used for testing purposes only.
    It should be long enough to fill up,
    in print, a couple of lines at least.}



\begin{document}

\Text \ornament

\Text \ornament[1cm plus 3mm minus 2mm]

% \showlists

\small

\Text \ornament

\Text \ornament[1cm plus 3mm minus 2mm]

\footnotesize

\Text \ornament

\Text \ornament[1cm plus 3mm minus 2mm]

\normalsize

\Text

\Text

\Text \ornament[4cm plus 1cm]

\Text

\Text \ornament[4cm plus 1cm]

\Text

However, this trick does not work as expected
if a new page is started with an explicit
\verb|\newpage| command.

\ornament

\newpage

\Text

\end{document}

Some remarks:

  1. I am a nasty guy who still loves to play around with internal LaTeX macros and with TeX primitives, as you can see from the code.

  2. Instead of loading the extsizes package, I use the extbook class: this makes no difference for the issue at hand, and is recommended.

  3. An optional argument in the \ornament command lets you specify the amount of vertical space that should be skipped; the default is \baselineskip, that is, the vertical space taken up by a line of printed text, in the current size.

  4. The code as it stands draws yellow rules, instead of white ones: this is done to let you see exactly where those rules are placed. You should change the code (in the obvious way) before deploying it.

  5. The code contains (commented out) diagnostic code that you can activate in order to see exactly what is placed on the vertical list being built.

Note, finally, that this trick will not work as expected if a new page is started with an explicit \newpage command.

For completeness’ sake, here is a picture of the first page of the output:

First page of the output of the code

  • 1
    That did the trick. Thanks so much! – skiasaurus Oct 13 at 2:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.