Le {lcr} de \begin{tabular}{lcr} est l’un des rares endroits de LaTeX où l’on écrit un programme plutôt que du texte. Au-delà du nombre de colonnes et de leur alignement, on peut y demander d’insérer une déclaration avant et après chaque cellule, de remplacer l’espace entre colonnes par autre chose, ou de répéter un groupe de colonnes. Et le vocabulaire de cette spécification de colonnes ne procède pas d’une conception unique : il s’est constitué par dons successifs. \newcolumntype venait à l’origine d’un package distinct de David Carlisle, newarray.sty, et le manuel d’array note que « David kindly agreed on the inclusion ». En partant de l, c, r et p{width}, cette page suit ce langage à travers m{width} et b{width}, >{…} et <{…}, @{…} et !{…}, *{n}{…}, w et W, jusqu’à la colonne X de tabularx qui fait atteindre au tableau une largeur exacte.
Quels spécificateurs demandent quel package
LaTeX seul ne fournit que l, c, r, p{width}, |, @{…} et *{n}{…}. Tout le reste — m{width}, b{width}, >{…}, <{…}, !{…}, w et W, ainsi que \newcolumntype — vient du package array (TeX Live 2024 fournit la v2.5g du 16 octobre 2023, de Frank Mittelbach). La colonne X vient de tabularx (v2.11c du 8 juillet 2023, de David Carlisle), qui exige lui-même array. Comme booktabs et tabularx chargent array en interne, il est souvent déjà actif ; écrire explicitement \usepackage{array} reste plus sûr.
Savoir laquelle tourne dans votre document se règle en une étape : écrire volontairement une lettre de colonne qui n’existe pas. LaTeX seul répond ! LaTeX Error: Illegal character in array arg., tandis qu’avec array chargé la plainte vient du package : ! Package array Error: Illegal pream-token. Donc, si vous avez écrit m{width} et qu’on vous répond « Illegal character », le message vous dit en réalité que vous avez oublié de charger array.
Colonnes de paragraphe p, m, b — et les largeurs fixes w et W
Il existe trois colonnes de paragraphe repliables, qui ne diffèrent que par la position verticale de la cellule. Selon le manuel d’array, p{width} équivaut à \parbox[t]{width} et est donc aligné en haut ; m{width} place son contenu au centre vertical de la ligne ; et b{width} « coincides with \parbox[b] », donc aligné en bas. La différence compte lorsqu’une ligne mêle une cellule haute — une colonne p repliée sur plusieurs lignes, ou une grande image — à des cellules d’une seule ligne. Avec le p par défaut, la voisine courte colle au haut de la ligne et ne s’aligne pas sur le milieu de la cellule haute ; m{width} les met naturellement au même niveau.
Pour une largeur fixe sans repli, array propose w{align}{width} et W{align}{width}. Les deux fonctionnent pour l’essentiel comme \makebox[width][align]{cell} : elles se comportent comme l, c ou r tout en figeant la largeur de la colonne. Elles diffèrent par leur manière d’échouer — w déborde silencieusement lorsque le contenu est plus large que la largeur, tandis que W émet un avertissement de boîte trop pleine dans la même situation. Attention toutefois : en cas de débordement, W dépasse toujours vers la droite, ce qui change l’alignement apparent. Si le besoin est « figer la largeur mais être prévenu en cas de débordement », W est la bonne réponse.
| Spécificateur | Position verticale / largeur | Repli ? | Fourni par |
|---|---|---|---|
p{wd} | Haut ; équivalent à \parbox[t]{wd} | Oui | Standard |
m{wd} | Centré verticalement sur la ligne | Oui | array |
b{wd} | Bas ; coïncide avec \parbox[b]{wd} | Oui | array |
w{l}{wd} | Comme \makebox[wd][l] ; déborde en silence | Non | array |
W{l}{wd} | Comme w mais avertit ; le débordement va à droite | Non | array |
X | Colonne p dont la largeur est calculée pour la cible | Oui | tabularx |
Deux petits réglages par défaut méritent d’être retenus pour les colonnes de paragraphe. D’abord, à l’intérieur de p, m et b, le retrait \parindent vaut 0 ; pour le rétablir, écrivez par exemple >{\setlength{\parindent}{1em}}p{5cm}. Ensuite, array ajoute une longueur nommée \extrarowheight. Avec une valeur positive, elle n’augmente que la hauteur de chaque ligne et laisse la profondeur inchangée — la prescription la plus directe contre les \hline qui semblent toucher le sommet des capitales. Le manuel d’array précise avoir réglé 1pt pour le tableau imprimé dans sa propre documentation.
Insérer autour de chaque cellule — >{…} et <{…}
Le cœur du package array, ce sont >{decl} et <{decl}. >{decl} insère decl juste avant le contenu de chaque cellule de la colonne, <{decl} juste après. Écrivez >{\bfseries}l et toutes les cellules d’une colonne alignée à gauche sortent en gras sans rien taper cellule par cellule. >{\itshape}c donne de l’italique centré, >{\color{red}}r du rouge aligné à droite. Pour les colonnes de paragraphe, on peut aussi y mettre des déclarations d’alignement : >{\raggedright}p{4cm} crée une colonne qui « se replie sans se justifier ».
Un piège sérieux guette pourtant. \raggedright, \raggedleft et \centering redéfinissent tous en interne le terminateur de ligne \\. Si une colonne qui en porte un dans >{…} est la dernière colonne du tableau, \\ cesse de terminer les lignes, le & de la ligne suivante déborde, et l’on obtient ! Extra alignment tab has been changed to \cr.. La cause est dans la spécification, mais l’erreur désigne une ligne du corps : d’où le fait que personne ne la repère du premier coup. Le remède est d’ajouter \arraybackslash d’array à la fin de la déclaration : >{\raggedright\arraybackslash}p{4cm} rétablit le terminateur. Sur une colonne qui n’est pas la dernière, cela ne nuit pas ; mieux vaut donc l’écrire systématiquement.
L’origine de \arraybackslash réserve une surprise. C’est tabularx qui l’a introduit, précisément pour réparer ce conflit avec \raggedright. Aujourd’hui, c’est array.sty lui-même qui porte \def\arraybackslash{\let\\\tabularnewline}, tandis que tabularx ne conserve qu’une définition de secours conditionnelle. Autrement dit, l’outil est né dans un package et habite désormais dans un autre.
\usepackage{array}
% ...
% bold labels; a ragged-right wrapping column; a whole column in math mode
\begin{tabular}{ >{\bfseries}l >{\raggedright\arraybackslash}p{5cm} >{$}c<{$} }
\hline
Symbol & Meaning & \multicolumn{1}{c}{Value} \\
\hline
c & Speed of light in vacuum, a defining constant. & 2.998\times10^{8} \\
g & Standard gravitational acceleration near the surface. & 9.807 \\
\hline
\end{tabular}Le >{$}c<{$} de la troisième colonne est précisément l’usage d’origine de > et <. Chaque cellule reçoit un $ avant et après, si bien que toute la colonne est composée en mathématiques en ligne et qu’on ne tape plus jamais $…$ dans une colonne riche en nombres ou symboles. À l’inverse, dans un environnement array dont les cellules sont déjà en mode mathématique, les deux $ s’annulent et placent cette seule colonne en mode texte. La ligne d’en-tête demande cependant de l’attention : un Value écrit tel quel est composé en mathématiques et ressort en italique aux espacements lâches. Comme dans l’exemple ci-dessus, \multicolumn{1}{c}{Value} ramène cette seule cellule en mode texte.
Retenez aussi la contrainte : seule une déclaration peut figurer dans >{…} et <{…}. Les formes sans argument suivant, comme \bfseries ou \itshape, conviennent, mais il ne faut pas terminer par une commande qui prend un argument. >{\textbf} se met à lire le contenu de la cellule comme argument et échoue de la manière la plus gênante : aucune erreur, et rien ne sort en gras. Le manuel d’array le dit clairement — >{\textbf} « would not make the whole column bold nor would it make the first character bold ». Pour le gras, utilisez la forme déclarative \bfseries.
À la frontière des colonnes — @{…} et !{…}
Entre deux colonnes, LaTeX insère par défaut un espace \tabcolsep — 6 pt de chaque côté, soit 12 pt au total. Placez @{decl} à cet endroit de la spécification et, selon les termes du manuel d’array, cela « suppresses inter-column space and inserts decl. instead » : l’espace disparaît et ce que vous avez écrit prend sa place. Deux usages principaux. D’abord, réduire le blanc extérieur du tableau : @{} (déclaration vide) aux deux extrémités supprime le \tabcolsep à gauche de la première colonne et à droite de la dernière, de sorte que le tableau s’aligne exactement sur le bord gauche du texte — idiome familier des tableaux booktabs. Ensuite, insérer un séparateur : séparez les nombres en une colonne de partie entière et une colonne de partie fractionnaire, mettez @{.} entre les deux, et les points s’alignent à position fixe, donnant l’alignement décimal.
Le pendant de @{…} est !{decl}. Il se place là où pourrait figurer un filet vertical | et insère un decl arbitraire à la place du filet. La différence décisive : !{…} ne supprime pas l’espace inter-colonnes normal. L’exemple du manuel d’array le rend concret : c!{\hspace{1cm}}c donne un écart égal à l’espace existant plus 1 cm, alors que c@{\hspace{1cm}}c donne exactement 1 cm. Si l’on veut une ligne pointillée entre colonnes tout en conservant le blanc (en y plaçant une commande d’arydshln), !{…} est le bon choix. Au passage, charger array change aussi le comportement de | : l’écart entre colonnes s’élargit de l’épaisseur du filet, alors qu’en LaTeX standard le filet se place dans l’espace existant sans modifier la largeur.
Répéter et nommer des colonnes — *{n}{…} et \newcolumntype
Quand de nombreuses colonnes identiques se suivent, *{count}{spec} les replie. Selon la définition du manuel d’array, cela équivaut à count copies de spec : six colonnes centrées deviennent *{6}{c} au lieu de cccccc. L’unité répétée peut contenir plusieurs spécificateurs : *{3}{|c}| se développe en |c|c|c|. Sa vraie valeur apparaît lorsque la spécification répétée est longue et contient >{…} ou @{…} : *{4}{>{$}c<{$}} construit quatre colonnes mathématiques centrées d’un seul coup.
Si la même combinaison revient partout dans un document, lui donner un nom avec \newcolumntype{letter}{…} se lit bien mieux. Le manuel d’array propose lui-même \newcolumntype{C}{>{$}c<{$}} en exemple ; ensuite, {C C C} suffit. \newcolumntype accepte le même argument optionnel que \newcommand, ce qui permet aussi de construire un type de colonne prenant la largeur en paramètre. Quand les définitions s’accumulent et qu’on s’y perd, écrivez \showcols : la liste de toutes les définitions \newcolumntype actives est envoyée dans le journal.
Faire tenir un tableau à une largeur cible — la colonne X de tabularx
Jusqu’ici, c’est vous qui décidiez de la largeur. Le cas inverse — « que tout le tableau fasse exactement \textwidth » — est la raison d’être de la colonne X de tabularx. Passez d’abord la largeur cible, comme dans \begin{tabularx}{\textwidth}{l X r}, et les colonnes marquées X sont élargies ou rétrécies par calcul pour combler l’écart. Ce qui rend X abordable, c’est la simplicité du mécanisme : comme l’écrit le manuel, la spécification X est convertie en p{some value} une fois la bonne largeur calculée. Dans le code, la valeur par défaut tient en une ligne : \newcommand{\tabularxcolumn}[1]{p{#1}}. X n’est donc rien d’autre qu’« une colonne p dont la largeur est remplie ensuite », et c’est précisément pourquoi les mêmes décorations fonctionnent : >{\raggedright\arraybackslash}X se comporte comme prévu. Pour centrer verticalement le contenu, il suffit de redéfinir : \renewcommand{\tabularxcolumn}[1]{m{#1}}.
\usepackage{tabularx}
% ...
% two X columns, the second twice as wide as the first
\begin{tabularx}{\textwidth}{@{}
l
>{\hsize=.667\hsize\linewidth=\hsize}X
>{\hsize=1.333\hsize\linewidth=\hsize}X @{}}
\hline
Key & Short note & Longer note \\
\hline
alpha & fits in the narrow column & twice as wide, so prose wraps less often \\
\hline
\end{tabularx}Par défaut, toutes les colonnes X finissent à la même largeur ; mais écrire >{\hsize=…\hsize\linewidth=\hsize}X comme ci-dessus modifie leurs poids. Le manuel impose toutefois deux règles : conserver inchangée la somme des largeurs des colonnes X (0,667 et 1,333 font ici 2, soit toujours deux colonnes X standard) et ne pas utiliser de \multicolumn traversant une colonne X, car le calcul de largeur n’en tient pas compte. En cas de comportement étrange, déclarez \tracingtabularx : le journal affichera les largeurs essayées à chaque passe.
Deux symptômes propres à X méritent d’être connus. Si les colonnes non-X totalisent déjà plus que la largeur cible, tabularx refuse d’attribuer une largeur négative aux colonnes X : il émet Package tabularx Warning: X Columns too narrow (table too wide) et les fixe par défaut à 1 em, si bien que le tableau sort plus large que demandé. Ensuite, le corps d’un tabularx est en réalité lu comme argument d’une commande et le tableau est recomposé plusieurs fois pendant la recherche des largeurs : un \verb à l’intérieur déclenche donc LaTeX Warning: \verb may be unreliable inside tabularx. La comparaison entre tabularx, tabulary et tabularray, ainsi que le cas des tableaux qui n’entrent pas du tout dans la page, relèvent de « tableaux larges et largeur automatique ».
Un exemple combiné, et la réponse moderne pour aligner les nombres
Pour finir, une spécification qui concentre les outils précédents. La colonne 1 est une colonne d’étiquettes en gras (>{\bfseries}l) ; la colonne 2 une colonne de paragraphe repliable alignée à gauche (>{\raggedright\arraybackslash}p{5cm}) ; les colonnes 3 et 4 des colonnes mathématiques centrées construites ensemble par *{2}{…} ; et le blanc extérieur est supprimé par @{} aux deux bouts. Loger plusieurs mécanismes sur une ligne est la force du langage des colonnes — et aussi ce qui le rend illisible : d’où l’intérêt pratique de nommer une combinaison fréquente avec \newcolumntype.
\usepackage{array}
% ...
\begin{tabular}{@{} >{\bfseries}l >{\raggedright\arraybackslash}p{5cm} *{2}{c} @{}}
\hline
Symbol & Meaning & Value & Unit \\
\hline
$c$ & Speed of light in vacuum, a defining constant. & $2.998\times10^{8}$ & m/s \\
$g$ & Standard gravity, an approximation near the surface. & $9.807$ & m/s$^2$ \\
\hline
\end{tabular}Une chose pour laquelle ce langage de colonnes vaut mieux ne pas être employé : aligner les nombres sur le séparateur décimal. Prenez la colonne S du package siunitx plutôt que le @{.} esquissé plus haut. La colonne S analyse chaque nombre et aligne correctement partie entière, séparateur décimal, partie fractionnaire, exposant et même incertitudes, tout en réglant au passage groupements de chiffres et chiffres significatifs. Au passage, le manuel d’array imprime son propre code d’alignement décimal puis y accole l’avertissement « the code is bad », renvoyant à une bien meilleure version dans le dcolumn.sty de David Carlisle — qu’un manuel de package juge ainsi son propre exemple est chose rare.