0

The context for this question is that I would like to vertically align text in a tabular.

I.e. I would like to choose whether the text is:

  • as close as possible to the top of the cell, or;
  • as close as possible to the bottom of the cell, or;
  • in the middle of the cell.

This is not what TeX means by "alignment", but it is what I mean here.

One way to do this is

\documentclass{article}
\usepackage[a4paper]{geometry}
\usepackage{array}
\usepackage{graphicx}

\begin{document}

\begin{tabular*}{4cm}{ p{4cm} }
  \hline
  \parbox[m][1.8cm][t]{4cm}{Some top-alignedcontent.}  \\
  \hline
  \parbox[m][1.8cm][c]{4cm}{Some middle-aligned content.}  \\
  \hline
  \parbox[m][1.8cm][b]{4cm}{Some bottom-aligned content.}  \\
  \hline
\end{tabular*}
\end{document}

This aligns the middle of the parbox to the cell baseline. It then aligns the text within the parbox either to the top, the middle, or the bottom.

But, that assumes that I can set the row height at 1.8 cm. In other cases, there are may be previous columns in the table which have fixed the row height. So, is there a way I can find out the current row height in a table?

Here's an example of what I mean:

\documentclass{article}
\usepackage[a4paper]{geometry}
\usepackage{array}
\usepackage{graphicx}

\begin{document}

\begin{tabular*}{4cm}{ p{4cm} p{4cm} }
  \hline
  There could be any old stuff here... &
  \parbox[m][1.8cm][t]{4cm}{Some top-aligned content.}  \\
  \hline
  ... of any width or height... &
  \parbox[m][1.8cm][c]{4cm}{Some middle-aligned content.}  \\
  \hline
  ... is there a variable I can use in the height argument to parbox,
  which will ensure it fits the whole cell height? &
  \parbox[m][1.8cm][b]{4cm}{Some bottom-aligned content.}  \\
  \hline
\end{tabular*}
\end{document}

What should I put instead of "1.8cm" in the parbox's height argument?

closed as unclear what you're asking by Zarko, Stefan Pinnow, Schweinebacke, Marco Daniel, Mico Mar 20 '17 at 23:00

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • Your question is not clear. Please, improve MWE with case of "previous" column. Of topic: \parbox hasn't option m, instead it use c, i. e.: change your table code to: \begin{tabular*}{4cm}{l} \hline \parbox[t][1.8cm][t]{4cm}{Some content.} \\ \hline \parbox[t][1.8cm][c]{4cm}{Some content.} \\ \hline \parbox[t][1.8cm][b]{4cm}{Some content.} \\ \hline \end{tabular*} – Zarko Mar 20 '17 at 12:50
  • 1
    as zarko says \parbox hasn't got an m option but perhaps you are just looking for the m column type and no nested parbox at all? – David Carlisle Mar 20 '17 at 13:12
2

I wasn't sure this would work, but I still wouldn't bother unless you want to play with proportional glue.

Note, I like to add \strut to the beginning and end of each \parbox.

\documentclass{article}
\usepackage[a4paper]{geometry}
\usepackage{array}
\usepackage{graphicx}

\newlength{\boxsize}

\newcommand{\setboxsize}[2]% #1 = width, #2=text
{\sbox0{\parbox{#1}{\strut #2\strut}}%
 \global\boxsize=\ht0
 \global\advance\boxsize by \dp0
 \box0}

\begin{document}

\begin{tabular}{ll}
  \hline
  \setboxsize{4cm}{There could be any old stuff here...} &
  \parbox[c][\boxsize][t]{4cm}{\strut Some top-aligned content.\strut}  \\
  \hline
  \setboxsize{4cm}{... of any width or height...} &
  \parbox[c][\boxsize][c]{4cm}{\strut Some middle-aligned content.\strut}  \\
  \hline
  \setboxsize{4cm}{... is there a variable I can use in the height argument to parbox,
  which will ensure it fits the whole cell height?} &
  \parbox[c][\boxsize][b]{4cm}{\strut Some bottom-aligned content.\strut}  \\
  \hline
\end{tabular}
\end{document}

This solution replaces tabular with a new environment (Tabular). It runs tabular twice, the first time saving the row heights (no output) and the second using them. It also introduces the \cell macro. which functions similar to \parbox.

Part of this solution was stolen from here.

\documentclass{article}
\usepackage{environ}

\makeatletter
\newcount{\cell@row}
\newlength{\cell@size}

\newcommand{\@cell}[3][c]% (first time) #1=tcb (optional), #2=width, #3=text
{\sbox1{\parbox{#2}{\topstrut #3\bottomstrut}}%
 \dimen0=\ht1
 \advance\dimen0 by \dp1
 \ifdim\cell@size<\dimen0 \global\cell@size=\dimen0\fi
 \expandafter\xdef\csname cell@size\the\cell@row\endcsname{\the\cell@size}%
}
\newcommand{\@@cell}[3][c]% (second time) #1=tcb (optional), #2=width, #3=text
{\parbox[c][\csname cell@size\the\cell@row\endcsname][#1]{#2}{\topstrut #3\bottomstrut}}

\NewEnviron{Tabular}[2][c]% #1 = tcb (optional), #2 = columns (same as tabular)
{\let\cell=\@cell
 \global\cell@row=0
 \global\cell@size=0pt
 \def\topstrut{\rule{0pt}{\arraystretch\ht\strutbox}}%
 \def\bottomstrut{\rule[-\arraystretch\dp\strutbox]{0pt}{0pt}}%
 \let\old@arraycr\@arraycr% executes at end of line
 \def\@arraycr{\global\advance\cell@row by 1
   \global\cell@size=0pt
   \old@arraycr}%
 \sbox0{\begin{tabular}{#2}
 \BODY
 \end{tabular}}%
 \let\cell=\@@cell
 \global\cell@row=0
 \def\@arraycr{\global\advance\cell@row by 1
   \old@arraycr}%
 \begin{tabular}[#1]{#2}
   \BODY
 \end{tabular}}
\makeatother

\begin{document}

\noindent\begin{Tabular}{llll}
  \hline
  \cell[t]{3cm}{\raggedright Some top-aligned content.} &
  \cell[c]{3cm}{\raggedright Some middle-aligned content.} &
  \cell[b]{3cm}{\raggedright Some bottom-aligned content.} &
  \cell{1cm}{\raggedright I saved the largest cell for last} \\
  \hline
\end{Tabular}

\end{document}

demo

  • Accepting. This answers my question... and more importantly it tells me there's no easier way. Indeed, for a complete solution I'd have to call setboxsize on each succeeding cell in a row, ensuring it took the max; and then, what if the text is taller than the previous rows? Gosh, guys; in HTML you type style='vertical-align:top' and in Word you click a little button. – dash2 Mar 21 '17 at 13:15
  • You should only do it for the largest cell in a row, and it needs to be done at the start of the row (you can delay \box0 until needed). – John Kormylo Mar 21 '17 at 15:16
  • Ah... but which will be the largest cell? Context: I'm writing code that spits out LaTeX and which can be called with different arguments. – dash2 Mar 21 '17 at 15:18
  • I could... but it's too much. I'm trying to let people use LaTeX, not to rewrite LaTeX to add functionality. I might go for a fudge like a zero-width centered starting cell, and then let alignments be t/c/b with respect to that. But I want to respect the constraints of the system, not to do some weird unique thing that may work on alternate Fridays. I'll keep watching for a table package with this functionality... tabu looked good but appears unmaintained, cals seems a little weird.... – dash2 Mar 21 '17 at 15:46
  • I thought of a new approach (and deleted several earlier comments). – John Kormylo Mar 21 '17 at 19:20
3

Your question isn't very clear as to the desired result but I think you want

enter image description here

\documentclass{article}
\usepackage[a4paper]{geometry}
\usepackage{array}
\usepackage{graphicx}

\begin{document}

\begin{tabular}{p{4cm}p{4cm} }
  \hline
  There could be any old stuff here... &
  Some content.  \\
  \hline
  \multicolumn{1}{m{4cm}}{... of any width or height...}&
  Some content.  \\
  \hline
  \multicolumn{1}{b{4cm}}{... is there a variable I can use in the height argument to parbox,
  which will ensure it fits the whole cell height?} &
  Some content.  \\
  \hline
\end{tabular}


\end{document}

Original guess:

enter image description here

\documentclass{article}
\usepackage[a4paper]{geometry}
\usepackage{array}
\usepackage{graphicx}

\begin{document}

\begin{tabular}{m{4cm}m{4cm} }
  \hline
  There could be any old stuff here... &
  Some content.  \\
  \hline
  ... of any width or height... &
  Some content.  \\
  \hline
  ... is there a variable I can use in the height argument to parbox,
  which will ensure it fits the whole cell height? &
  Some content.  \\
  \hline
\end{tabular}
\end{document}

Note I used tabular not tabular* as your specification was for a total width of 4cm, and two columns, each of width 4cm+12pt \tabcolsep padding, which clearly can not fit.

  • I will try to clarify my question. Concretely, in the example, I would like the first row to be top-aligned, the second row to be middle-aligned, and the third row to be bottom-aligned, in the sense I describe in the question. – dash2 Mar 20 '17 at 14:47
  • @dash2 OK I added a second version – David Carlisle Mar 20 '17 at 14:55
  • It's a good try and it works for the example. But the problem is, I do not know what will be in those first cells in the row! They might themselves be upper or lower aligned, for example. And I might want a third column which has a different alignment from the first. In other words, I want the cell itself to determine its own alignment... Maybe I could have an empty width 0 column before each cell? (Sigh... this whole system is so broken :-/) – dash2 Mar 20 '17 at 15:52
  • I should add that this is why I came up with the parbox solution in the first place - it doesn't rely on setting up the previous cell in a particular way. But, I am open to other solutions. – dash2 Mar 20 '17 at 15:53
  • @dash2 you are not using "alignment" the way it is used in TeX. a tabular row has a single baseline row for the entire row, each cell has a baseline that is placed on the row's baseline. lcr entries just have one line so their baseline goes on the row baseline. p entries have baseline based on their top row, m on the vertical centre and b on the bottom row. So the alignment of Some Content is unchanged in the three rows in the new example, it is the alignment of the first column that you are changing to place its first line, last line or centre on the reference line for the row. – David Carlisle Mar 20 '17 at 17:21

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