The [t]
and [b]
optional arguments of minipage
already use the baselines of the first and last line, and not the top or bottom of the surrounding box. AFAIK most of such vertical positioning options in LaTeX address baselines. Here three minipage
s with [t]
, [c]
(or without) and [b]
options (code below):

If this wouldn't be the case I would use \raisebox{\dimexpr-\height+\ht\strutbox\relax}{<content>}
and \raisebox{\dimexpr\depth-\dp\strutbox\relax}{<content>}
for the first and last baseline, respectively. This depends on the content, but would be accurate if both lines contain a \strut
.
Update:
About the issue with \color
: This macro apparently adds some vertical space because at the beginning of minipage
TeX is still in vertical mode. To avoid this use \leavevmode
before \color
(as \textcolor
does internally). This will change to horizontal mode and avoid the misalignment. Added a \strut
before \color
should actually do the same, because it also starts horizontal mode.
\documentclass{article}
\usepackage{lipsum}
\begin{document}
before
\begin{minipage}[t]{1cm}
First\\
Middle\\
Last
\end{minipage}
between
\begin{minipage}[c]{1cm}
First\\
Middle\\
Last
\end{minipage}
between
\begin{minipage}[b]{1cm}
First\\
Middle\\
Last
\end{minipage}
after
\end{document}
First method
This code is Plain TeX, but can be used also in LaTeX; the macro \centervbox
takes as argument a box register number and outputs the same box, but centered with respect to the margins.
\catcode`\@=11
\def\centervbox#1{\begingroup\global\setbox\@ne=\box\voidb@x
\setbox\z@=\copy#1\relax\docentervbox}
\def\docentervbox{%
\setbox\z@=\vbox{\unvbox\z@ \setbox\tw@=\lastbox
\skip@=\lastskip\unskip
\global\setbox\@ne=\vbox{
\vskip\skip@
\hbox to\hsize{\hfil\box\tw@\hfil}
\unvbox\@ne}}%
\ifdim\ht\z@=\z@
\def\next{\unvbox\@ne\endgroup}%
\else
\let\next\docentervbox
\fi
\next}
\catcode`\@=12
\vsize=5\baselineskip
\setbox4=\vbox{
\halign{\hfil#&\hfil#\hfil&#\hfil\cr
aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
d & eee & f\cr}
}
\centervbox{4}
\bye
In the example I've used box register 4, but if you say \newbox\mybox
and then
\setbox\mybox=\vbox{...}
then you can say \centervbox\mybox
. The box register remains untouched (if it's not box register 1, but using this would be a very bad thing).
Comments to the first method
We assume that there is already a box built as a \vbox
in a box register, that is something like \setbox\mybox=\vbox{...}
and that this box contains only hboxes and glue between them. The procedure is to copy this box into a scratch box (number 0); we reserve also box register 1, on which we'll act always globally, first of all ensuring it's void. Then we start the recursion: at each step we retrieve the bottom hbox from box 0 and transfer it into box 1; we also transfer the interline glue. However, the retrieved box is put inside a box as wide as \hsize
and centered in it.
The recursion ends when the height of box 0 is zero. At that point we \unvbox
box register 1.
Second method
An alternative way to do the same is to typeset twice the alignment, first gathering its natural width and then with the desired preamble:
\newdimen\alignlen \newtoks\preamble
\long\def\centeralign#1#2{\par\preamble{#1}%
\setbox0=\vbox{\tabskip=0pt\halign{&##\cr#2\crcr}}%
\alignlen=\wd0
\begingroup\tabskip=0pt plus 1fil
\halign to\hsize{\tabskip=0pt \the\preamble\tabskip=0pt plus 1fil\cr
#2\crcr}\endgroup}
\bigskip
\centeralign{\hfil#&\hfil#\hfil&#\hfil}
{aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
aa & b & cc\cr
d & eee & f\cr}
This requires a slightly different syntax, but not so complicated. First the alignment is typeset in a box with a standard preamble, nothing more than "print each entry". The length register \alignlen
is loaded with the width. Then the alignment is typeset with infinite glue on each side, with the desired preamble. Since the \halign
is outside any box, it can be split across pages. This method has the advantage that \noalign
commands can be put after \cr
, stating penalties and vertical skips.
Comments to the second method
If the box to center is an \halign
we can use a different method. First of all we typeset the \halign
inside a box with a trivial preamble &#\cr
means "any number of columns with left alignment"; this will give the possibility to measure the natural width of the alignment, as requested.
Then we typeset the alignment with the requested preamble, but with infinitely stretchable \tabskip
glue at both sides. The preamble had been saved in the token register \preamble
, we simply augment it by adding \tabskip=0pt
which will hold for all intercolumn spacing, at the start and the infinite glue specification for the spacing at the right.
Third method
It's possible to carry in the newly formed box also kerns and penalties, in addition to skips and boxes. No other items can come along.
\catcode`\@=11
\newif\ifboxended
\def\centervbox#1{\begingroup\global\setbox\@ne=\box\voidb@x
\global\boxendedfalse
\setbox\z@=\copy#1\relax\docentervbox}
\def\docentervbox{%
\setbox\z@=\vbox{\unvbox\z@
\ifcase\lastnodetype
% char node (can't remove)
\or
% hlist node
\setbox\tw@=\lastbox
\def\next{%
\global\setbox\@ne=\vbox{
\hbox to\hsize{\hfil\box\tw@\hfil}\unvbox\@ne}}%
\or
% vlist node
\setbox\tw@=\lastbox
\def\next{%
\global\setbox\@ne=\vbox{
\hbox to\hsize{\hfil\box\tw@\hfil}\unvbox\@ne}}%
\or
% rule node (can't remove)
\or
% ins node (can't remove)
\or
% mark node (can't remove)
\or
% adjust node (can't remove)
\or
% ligature node (can't happen)
\or
% disc node (can't happen)
\or
% whatsit node (can't remove)
\or
% math node (can't remove)
\or
% glue node
\skip@=\lastskip\unskip
\def\next{\global\setbox\@ne=\vbox{\vskip\skip@\unvbox\@ne}}%
\or
% kern node
\dimen@=\lastkern\unkern
\def\next{\global\setbox\@ne=\vbox{\kern\dimen@\unvbox\@ne}}%
\or
% penalty node
\count@=\lastpenalty\unpenalty
\def\next{\global\setbox\@ne=\vbox{\penalty\count@\unvbox\@ne}}%
\or
% unset node (can't happen)
\or
% math mode node (can't remove)
\else
% empty list
\def\next{\global\boxendedtrue}
\fi
\next}
\ifboxended
\def\next{\unvbox\@ne\endgroup}
\else
\let\next\docentervbox
\fi
\next}
\catcode`\@=12
The list of node types can be found in the documentation of e-TeX (texdoc etex
). The special case -1 is when the list is empty, which we use to end the recursion.
Best Answer
The package
ragged2e
provides enhanced versions of\centering
,\raggedright
and\raggedleft
(that you may or may not like), but above all makes available the commandthat undoes the above declarations.