31

I am trying to understand the difference between \hfil and \hfill. I always thought that these commands were roughly equivalent except that \hfill was "stronger" than \hfil. As a result, I thought that I could centre a line of text using either of the lines:

\hfil Horizontally centred \hfil

\hfill Horizontally centred \hfill

It turns out that only the first of these snippets actually horizontally centers the text but I do not understand why.

There is a similar issue with \vfil and \vfill. My understanding is that \vfill can be defined as \vspace{\fill}, so it makes sense that you cannot vertically center some text using

\vfill Vertically centered \vfill

because \vspace is ignored at the top of the page. By the same reasoning,

\vspace*{\fill} Vertically centred\vfill

should work and it does, although not quite perfectly. In a similar way, you can use \hspace*{\fill} to horizontally centre text.

Is anyone able to clear explanation of what the differences are between \hfil and \hfill, and between \vfil and \vfill? I am aware of the post What is the difference between 'fil' and 'fill'? but this does not help me.

In trying to understand what is going on I created the following MWE:

\documentclass{article}
\usepackage[paperheight=40mm, paperwidth=80mm,showframe]{geometry}
\parindent=0pt
\begin{document}

  \hfil Horizontally centred \hfil

  \hfill Horizontally centred \hfill

  \hspace*{\fill} Horizontally centred \hfill

  \hfill Horizontally centred \hspace*{\fill}

  \hfil Horizontally centred \hspace*{\fill}

  \newpage

  \vfil Vertically centred\vfil

  \newpage

  \vfill Vertically centred\vfill

  \newpage

  \vspace*{\fill} Vertically centred\vfill

\end{document}

which produces the four pages:

enter image description here

Of course, I know that I can centre text with either

\centerline{Horizontally centred}

\begin{center}Horizontally centred\end{center}

but that's not what I am asking....although I am not convinced that I know the best way to vertically centre text!

2
  • 2
    In my mental picture \hfil and friends always need something to push against. So I tend to add struts. AFAIR \hspace* automatically adds "stomething to push against
    – daleif
    Feb 18, 2020 at 8:58
  • @daleifb Thanks! That's a very clean explanation.
    – user30471
    Feb 18, 2020 at 9:24

1 Answer 1

26

The first case: \hfil Horizontally centred \hfil\par (the blank line adds \par).

When \par is processed, the first thing TeX does is \unskip, then it adds a very high penalty, so the next added glue \hskip\parfillskip is not removed. Since the default value of \parfillskip is 0pt plus 1fil, you get centering. Almost, because you have a space after “centred” that's not removed.

The second case: \hfill text\hfill\par (the blank line adds \par).

This works as before, but now the \parfillskip glue is killed by \hfill.

The third case is essentially the same as the second one.

The fourth case: \hfill Horizontally centred \hspace*{\fill} almost centers the text (the space after “centred”, remember), because \unskip doesn't remove \hspace*{\fill} (it internally ends with another glob of glue just for this), because \parfillskip glue is killed.

The fifth case: the \hfil glue at either sides (explicit and provided by \parfillskip respectively) are killed by \hspace*{\fill}.

How do you achieve centering? With

\par{\centering Horizontally centred\par}

For vertical centering,

  1. you have to kill the \topskip glue and the baseline skip glue at the top and the bottom
  2. use \vspace*{\fill} at the top and \vfill (or a more symmetrical \vspace*{\fill}) at the bottom.
\documentclass{article}
\usepackage[paperheight=40mm, paperwidth=80mm,showframe]{geometry}

\setlength{\parindent}{0pt}

\begin{document}

\vspace*{-\topskip}
\vspace*{\fill}
\nointerlineskip
Vertically centred\par
\nointerlineskip
\vfill

\end{document}

enter image description here

5
  • Thanks. So, it's all about the glue being killed. So what is the recommended way to vertically centre?
    – user30471
    Feb 18, 2020 at 9:23
  • In the first case is there really a space that is not removed? To me it looks like the difference is actually caused by paragraph indentation since \noindent\hfil text\hfil centers the text.
    – user30471
    Feb 18, 2020 at 9:49
  • 1
    @Andrew The space preceding \hfil is not removed: \unskip does a single glue removal. Since you set \parindent to 0pt, using \noindent is redundant.
    – egreg
    Feb 18, 2020 at 9:52
  • Thanks, I was looking at a different example where I had the default \parindent....
    – user30471
    Feb 18, 2020 at 10:09
  • 3
    @Andrew Using \showoutput can help a lot to discover the implicitly-added skips, or to see that whatever skip you thought you added was discarded (at the beginning of a line or page) or removed by \unskip.
    – frougon
    Feb 18, 2020 at 10:52

You must log in to answer this question.