[Tex/LaTex] How to control the starting text position within a multicols environment

multicol

The text starting position varies wildly in the multicols environment depending on font size. If you pick a large font size, the text touches the top; but if you pick a small font size, the text sits very low. This looks very lopsided. How do I fix it?

\documentclass[12pt]{article}
\usepackage{multicol}

\setlength{\columnseprule}{0.4pt}

\newcommand{\m}{\begin{multicols}{2}
  \noindent
  this is a test\\
  this is a test\\
  this is a test\\
  this is a test
\end{multicols}}

\begin{document}
  \Huge\m
  \normalsize\m
  \tiny\m
\end{document}

Ugly multicols

Best Answer

The use case for which multicolhas been written is to mimic page creation as it normally happens execpt that instead of a single column several columns are produced. That means that on the top of each column \topskip is used to position the first line of the multicols environment.

\topskipis a register that is normally not changed throughout the document (even if the fontsize is changing in some places within the document). This is done so that the first line on a page is "usually" at the same position. The value for \topskipis typically defined by the class, i.e., if you specify 12pt as an option to the class the default font size will be 12 points and the \topskip will be 12 points as well (while the \baselineskip will be something like 14.4pt).

In your use case this may look a little strange, but as I said, the package wasn't written for this use case that the whole body of the environment would be in a different font size and if say you have a tiny font in the first line of the first column but a normal font in the second column then the multicol approach would make it come out right whereas with \topskipchanging with the font size this would look rather uneven then.

Also, page breaking is an asynchronous operation, so the \topskip changed by a font size command within the text may happen at the wrong place as TeX decides to break earlier or later.

So one way to cater for your use case is to change \topskip for the time multicolsis active, it is possible to do that inside the environment so that the old topskip value will be restored once the environment changes, e.g.

\documentclass[12pt]{article}
\usepackage{multicol}

\setlength{\columnseprule}{0.4pt}

\newcommand{\m}[1]{\begin{multicols}{2}
  #1\setlength\topskip{.7\baselineskip}%              set font and \topskip
  \noindent
  this is a test\\
  this is a test\\
  this is a test\\
  this is a test
\end{multicols}}

\begin{document}
  \m{\Huge}
  \m{\normalsize}
  \m{\tiny}
\end{document}

Now the font and the topskip value are only changes during the env body and you will get the following output:

enter image description here

Instead of making it 70% of the \baselineskip one could of course supply some explicit value or a different fraction. Less than 60% or so doesn't do anything because the characters will occupy that amout already.