The Problem

I want to create a table with an exact width. So I thought I'd use the tabular* environment. Then I realised, that it might be a little more difficult than I imagined in the beginning. The problem is the horizotal alignment/positioning: \tabcolsep and \arrayrulewidth change the positioning.

Consider the following:

\documentclass[varwidth=3.5cm,margin=2mm]{standalone}

\setlength{\arrayrulewidth}{.6pt}
\setlength{\tabcolsep}{0pt}
\begin{document}
\textbf{No packages}\par\vspace{5pt}
\begin{tabular*}{14mm}{ |@{} p{7mm} @{}|@{} p{7mm} @{}| } % 1: shifts---because of the vlines
\hline
\hspace{2pt}foo & \hspace{2pt}bar
\end{tabular*} (1)
\par\vspace{5pt}

\verb|\tabcolsep=0pt|\par
\begin{tabular*}{14mm}{ | p{7mm} | p{7mm} | } % 2: default, alignment is correct
\hline
\hspace{2pt}foo & \hspace{2pt}bar
\end{tabular*} (2) default

\begin{tabular*}{14mm}{% 3: manually corrected outer vertical line
@{\kern.5\arrayrulewidth}|@{\kern-\arrayrulewidth}%
p{7mm} | p{7mm}%
@{\kern-.5\arrayrulewidth}| }
\hline
\hspace{2pt}foo & \hspace{2pt}bar
\end{tabular*} (3) fixed1
\par\vspace{5pt}

\verb|\tabcolsep=2pt|\par
\setlength{\tabcolsep}{2pt}
\begin{tabular*}{14mm}{ | p{7mm} | p{7mm} | } % 4: default, alignment is NOT correct
\hline
foo & bar
\end{tabular*} (4) default

\begin{tabular*}{14mm}{% 5: manually corrected with tabcolsep active
@{\kern.5\arrayrulewidth}|%
p{\dimexpr 7mm-2\tabcolsep-.5\arrayrulewidth\relax}%
|%
p{\dimexpr 7mm-2\tabcolsep-.5\arrayrulewidth\relax}%
|}
\hline
foo & bar
\end{tabular*} (5) fixed2

\begin{tabular*}{14mm}{% 6: manually corrected(2) with tabcolsep active
p{\dimexpr 7mm-2\tabcolsep-0 \arrayrulewidth\relax}%
p{\dimexpr 7mm-2\tabcolsep-.5\arrayrulewidth\relax}%
|}
\hline
foo & bar
\end{tabular*} (6) fixed3
\end{document}


First impression: the left vline is not aligned with the table border. As one can see, I first tried to get rid of all \tabcolseps manually (1). This still has the widths of the vlines though. Curiously, the default behaviour with \tabcolsep=0pt does manage shifts caused by the vlines (2). One can fix the ugly outer vlines (not matching the edge of the table) manually (3). But this still leaves the problem of horizontal spacing in the cells. One could put a shifted parbox in there. A lot of work for many cells. So it might be better to use \tabcolsep. If I do, the default behaviour is shown in (4). Not working correctly, so one has to start fixing again. Curiously, this time one has to consider the width of the vlines in the fix (5). Obviously this is the better solution compared to (3). But this leads to potentially many manual adjustments with big tables, especially if there are not vlines between every column, as this has to be considered (6).

With package array

Trying to use one of the packages that should improve the behaviour of tables, I tried the array package:

\documentclass[varwidth=3.5cm,margin=2mm]{standalone}
\usepackage{array}
\setlength{\arrayrulewidth}{.6pt}
\setlength{\tabcolsep}{0pt}
\begin{document}
\textbf{array package}\par\vspace{5pt}
\begin{tabular*}{14mm}{ |@{} p{7mm} @{}|@{} p{7mm} @{}| } % 1: shifts---because of the vlines
\hline
\hspace{2pt}foo & \hspace{2pt}bar
\end{tabular*} (1)
\par\vspace{5pt}

\verb|\tabcolsep=0pt|\par
\begin{tabular*}{14mm}{ | p{7mm} | p{7mm} | } % 2: default, alignment is correct
\hline
\hspace{2pt}foo & \hspace{2pt}bar
\end{tabular*} (2) default

\begin{tabular*}{14mm}{% 3: manually corrected outer vertical line
|@{\kern-\arrayrulewidth}%
p{7mm}%
@{\kern-.5\arrayrulewidth}|@{\kern-.5\arrayrulewidth}%
p{7mm}%
@{\kern-\arrayrulewidth}| }
\hline
\hspace{2pt}foo & \hspace{2pt}bar
\end{tabular*} (3) fixed1
\par\vspace{5pt}

\verb|\tabcolsep=2pt|\par
\setlength{\tabcolsep}{2pt}
\begin{tabular*}{14mm}{ | p{7mm} | p{7mm} | } % 4: default, alignment is NOT correct
\hline
foo & bar
\end{tabular*} (4) default

\begin{tabular*}{14mm}{% 5: manually corrected with tabcolsep active
|%
p{\dimexpr 7mm-2\tabcolsep-1.5\arrayrulewidth\relax}%
|%
p{\dimexpr 7mm-2\tabcolsep-1.5\arrayrulewidth\relax}%
|}
\hline
foo & bar
\end{tabular*} (5) fixed2

\begin{tabular*}{14mm}{% 6: manually corrected(2) with tabcolsep active
p{\dimexpr 7mm-2\tabcolsep-0\arrayrulewidth\relax}%
p{\dimexpr 7mm-2\tabcolsep-1\arrayrulewidth\relax}%
|}
\hline
foo & bar
\end{tabular*} (6) fixed3
\end{document}


The left alignment of the vline seems to be corrected automatically, good. Sadly, this isn't really improving the overall result: To the right, the same issues appear. (1) is the same as before with corrected left vline. (2) shows the default behaviour with \tabcolsep=0pt. Again, manual fixing is needed (3). Better is to use \tabcolsep though. The default behaviour is shown in (4). This obviously has to be fixed as well (5). Here the situation is even worse than without the arrays package. One has to consider whether the column is an outer column or not, in order to fix the parbox widths. This doesn't get better if some vlines are not used (6). tabularx result looks similar. There is always the need to adjust manually.

tabularx package

\documentclass[varwidth=3.5cm,margin=2mm]{standalone}
\usepackage{tabularx}
\setlength{\arrayrulewidth}{1pt}
\setlength{\tabcolsep}{2pt}
\begin{document}
\textbf{tabularx package}\par\vspace{5pt}

\begin{tabular*}{14mm}{% 1: target layout
|%
p{\dimexpr 7mm-2\tabcolsep-1.5\arrayrulewidth\relax}%
|%
p{\dimexpr 7mm-2\tabcolsep-1.5\arrayrulewidth\relax}%
|}
\hline
foo & bar
\end{tabular*} (1) target

\begin{tabularx}{14mm}{ |X|X| }% default without manual sizing
\hline
foo & bar
\end{tabularx} (2) default1

\begin{tabularx}{14mm}{ |>{\hsize=7mm}X|X| }
\hline
foo & bar
\end{tabularx} (3) default2

\begin{tabularx}{14mm}{ |>{\hsize=\dimexpr7mm-2\tabcolsep-1.5\arrayrulewidth\relax}X|X| }
\hline
foo & bar
\end{tabularx} (4) fixed
\end{document}


This does some things better (e.g. right vline is always aligned), but one still has to do manual calculations based on vlines before or after...

Correct tables by default?

I would like to use a normal environment without the need to adjust it manually. Something like

\newlength{\mylength}
\def\mylength{-2\tabcolsep-.5\arrayrulewidth}


could work, if I can make them sensitive to the context vlines. Using array,

\newcolumntype{P}[1]{>{\raggedright\arraybackslash}p{\dimexpr#1-2\tabcolsep-\arrayrulewidth\relax}}


could work almost automated, if it could see surrounding vlines. I don't want to create a ton of column types and take care of which one to take (outer, inner column, surrounded by zero, one, two vlines).

How can I get a table of the predefined width without manual interaction?

• Did you try tabularx (which, incidentally, loads array)? – Bernard Jul 7 '18 at 16:40
• Yep, exactly the same as array for my tests. – nox Jul 7 '18 at 16:43
• If you do in the very first example \begin{tabular*}{14mm}{|@{}p{7mm}@{\hspace*{-2\arrayrulewidth}}|@{}p{7mm}@{\hspace*{-\arrayrulewidth}}|} then the gaps disappear. Same for \begin{tabular*}{\dimexpr14mm+3\arrayrulewidth}{|@{}p{7mm}@{}|@{}p{7mm}@{}|}, in which case the width between the vlines is 7mm each. – user121799 Jul 7 '18 at 16:50
• I have an error of 0.01mm, maybe due to the thickness pdf viewer measurement ruler. – Bernard Jul 7 '18 at 16:52
• @marmot this is working, but still manual adjustment is needed depending on the used vlines, similar to my tries above. – nox Jul 7 '18 at 17:25

Try this simple code:

\documentclass[varwidth=3.5cm,margin=2mm]{standalone}
\usepackage{tabularx}
\setlength{\arrayrulewidth}{.6pt}
\setlength{\tabcolsep}{0pt}

\begin{document}

\textbf{tabularx package}\par\vspace{5pt}
\begin{tabularx}{14mm}{ |X|X| }
\hline
\hspace{2pt}foo & \hspace{2pt}bar \\
\hline
\end{tabularx} (1)
\par\vspace{5pt}

\end{document}


• Oh, I just tried to use tabularx without using the correct environment ^^'. One should mention that you can define the width of single or multiple X columns by preceding >{\hsize=7mm}. Works! – nox Jul 7 '18 at 17:03
• One still needs a little calculation, but without exceptions: Using \begin{tabularx}{14mm}{ |>{\hsize=\dimexpr7mm-2\tabcolsep\relax}X|X| } does exactly what I needed, thanks! – nox Jul 7 '18 at 17:15
• That' not exact. The syntax is \hsize=coefficient \hize, to set relative sizes, the condition being that the sum of the coefficients be equal to the number of X columns. – Bernard Jul 7 '18 at 17:15
• I don't understand how you trick works, but all those calculations are normally done by the package. – Bernard Jul 7 '18 at 17:16
• Well, I just calculate the (absolute) correct size for the parbox used. Your \hsize=..\hsize is relative of course. – nox Jul 7 '18 at 17:20

It's not completely clear what the requirements are but as far as I can see you want a table with two equal columns, three vertical rules and a total width of 14mm, for that I would do the following.

\documentclass{article}
\usepackage{lmodern}

\usepackage{array}
\newlength\zz

\begin{document}

\setlength\zz{\dimexpr 14mm - 4\tabcolsep-3\arrayrulewidth}
\setlength\tabcolsep{2pt}
\fontsize{3.5pt}{4pt}\selectfont

\begin{tabular}{|p{.5\zz}|p{.5\zz}|}
foo  &bar\\
zz&zzz
\end{tabular}

\end{document}

• It's working, indeed. It looks better as there is not that much fine-tuning needed as in my example. Initially I was looking for a more general approach. One that automatically adjusts to the amount vlines with my choice of lengths for the parboxes. I see now, why tabularx is using relative measurement, too. – nox Jul 7 '18 at 18:16
• There are no real requirements, I am just trying to get used to (la)tex with it's details. – nox Jul 7 '18 at 18:43
• @nox that's what the code above does you just need to subtract the widths of the vertical lines and 2\tabcolsep table padding for each column, and then distribute the remaining space to your columns. Of course in 99 cases out of 100 the table is better set without verical lines (see the booktabs package documentation for a treatise on the evils of vertical lines in tables:-) – David Carlisle Jul 7 '18 at 19:51

You could define a phantom vrule that takes the same space as a standard rule. Or the other way round a vrule that doesn't take space:

\documentclass{article}
\usepackage{array}
\setlength\arrayrulewidth{4pt} %for better view

\newcolumntype\pvline{!{\hspace{\arrayrulewidth}}}

\newcolumntype\vline{!{\hspace{-0.5\arrayrulewidth}\vrule width \arrayrulewidth\hspace{-0.5\arrayrulewidth}}}

\begin{document}
\begin{tabular}{p{\dimexpr1cm-2\tabcolsep}|p{\dimexpr1cm-2\tabcolsep}}
\hline
blb& blb \\
blb&blbl
\end{tabular}

\begin{tabular}{p{\dimexpr1cm-2\tabcolsep}\pvline p{\dimexpr1cm-2\tabcolsep}}
\hline
blb& blb
\end{tabular}

\bigskip

\begin{tabular}{p{\dimexpr1cm-2\tabcolsep}\vline p{\dimexpr1cm-2\tabcolsep}}
\hline
blb& blb\\
blb&blbl
\end{tabular}

\begin{tabular}{p{\dimexpr1cm-2\tabcolsep} p{\dimexpr1cm-2\tabcolsep}}
\hline
blb& blb
\end{tabular}

\end{document}


• Works as intended, but still the placement of the outer vlines has not been corrected then. – nox Jul 7 '18 at 17:09
• If you mean in the second case: that's one of the reasons why array takes the width of the lines into account, so I would prefer the first solution. Regarding tabularx: be aware that it can be difficult to handle if \multicolumn is involved. – Ulrike Fischer Jul 7 '18 at 17:32