Tableaux sur plusieurs pages (longtable)

Un tableau placé dans l’environnement table ne se coupera jamais sur deux pages, quel que soit son nombre de lignes — et lorsqu’il déborde, rien ne proteste. Sous TeX Live 2024, un tableau de 119 lignes enfermé dans un flottant a produit une page au lieu de trois, les lignes restantes glissant silencieusement sous le bord de la feuille. Le package longtable de LaTeX fait tomber ce mur. Mais le vrai travail de longtable n’est pas de couper les pages : c’est d’aligner les colonnes sur toutes les pages. Pour cela, il inscrit ses mesures dans le fichier .aux et réclame une seconde compilation par l’avertissement Table widths have changed. Rerun LaTeX. Cette page suit ce que cette seconde passe achète, mesures à l’appui, face à supertabular qui s’en dispense.

Pourquoi un tableau dans un flottant ne se coupe jamais

Parce que table, comme figure, est un flottant, et que LaTeX traite un flottant comme une boîte indivisible tenant sur une page. La boîte se déplace d’un bloc vers le haut ou le bas d’une page, et ce qui se déplace d’un bloc ne peut pas être coupé en deux. Quelle que soit la hauteur du tabular intérieur, il n’est donc jamais scindé ; s’il ne tient pas, il sort tout simplement du papier. Le plus désagréable : cela ne déclenche aucun avertissement. Avec les mêmes 119 lignes de données, la version enfermée dans un flottant a donné une page, la version libre trois. Pas un seul message d’erreur. C’est le genre d’accident qu’on ne découvre qu’en lisant le PDF jusqu’au bout.

Un « tableau qui s’étend sur plusieurs pages » est donc fondamentalement incompatible avec le mécanisme des flottants. Il faut un moyen de placer le tableau dans le même flux que le texte et de le confier à l’algorithme de saut de page de TeX, comme on le fait d’un paragraphe. C’est longtable. Il a été écrit par David Carlisle, auteur d’array, tabularx et dcolumn, et fait partie du bundle tools livré avec toute installation LaTeX : rien à installer.

Écrire un longtable : ce qui change par rapport à tabular

Presque tout se passe comme avec tabular. Chargez \usepackage{longtable}, ouvrez par \begin{longtable}{l l r} — la spécification de colonnes est un argument obligatoire —, séparez les colonnes par & et terminez les lignes par \\. Les types l, c, r, p{width} fonctionnent, ainsi que \hline et \multicolumn. Trois choses seulement diffèrent. D’abord, ne l’enfermez jamais dans un environnement table : cela en refait un flottant et ramène le problème d’une seule page vu plus haut. Ensuite, un argument optionnel de position [c], [r] ou [l] peut précéder la spécification de colonnes. Enfin, longtable possède sa propre légende (voir plus bas). Les sauts de page n’ont lieu qu’entre deux lignes ou à un \hline, jamais au milieu d’une cellule d’une colonne p.

La position et les blancs alentour dépendent de longueurs modifiables à tout moment après \begin{document}. Sous TeX Live 2024, les valeurs par défaut mesurées sont : \LTleft et \LTright valent toutes deux 0pt plus 1fill — poussée égale des deux côtés, ce qui centre le tableau. Pour un tableau aligné à gauche, gardez \setlength{\LTright}{0pt plus 1fill} et posez \setlength{\LTleft}{0pt}. Les blancs au-dessus et au-dessous sont \LTpre et \LTpost, tous deux à 12pt plus 4pt minus 4pt par défaut.

Répéter en-tête et pied sur chaque page : endhead et endfoot

On déclare quatre marqueurs en tête du tableau, chacun disant « répéter les lignes jusqu’ici sur telles pages ». Un marqueur se place en fin de ligne à la place du \\. Les quatre sont facultatifs ; si le même en-tête convient à toutes les pages, \endhead suffit.

MarqueurOù apparaissent les lignes précédentesContenu typique
\endfirstheaden tête de la première page seulement\caption{…} et les titres de colonnes
\endheaden tête de toutes les pages sauf la première« (continued) » et les titres de colonnes
\endfootpied de chaque page qui continue (toutes sauf la dernière)une ligne « Continued on next page »
\endlastfoottout à la fin du tableau, dernière page seulementle filet de clôture ou une note
\killnulle part — la ligne sert seulement à mesurerune ligne factice aux entrées les plus larges
document.tex
\documentclass{article}
\usepackage{longtable}
\begin{document}

\begin{longtable}{l l r}
  % head of the first page only
  \caption{Annual sales log}\\
  \hline
  Date & Item & Amount \\
  \hline
  \endfirsthead

  % head of every later page
  \multicolumn{3}{l}{\small (continued)}\\
  \hline
  Date & Item & Amount \\
  \hline
  \endhead

  % foot of every page that continues
  \hline
  \multicolumn{3}{r}{\small Continued on next page}\\
  \endfoot

  % foot of the last page
  \hline
  \endlastfoot

  % everything below the markers is real data
  2026-01-05 & Apple  & 380 \\
  2026-01-06 & Orange & 120 \\
  % ...rows continue; pages are broken automatically...
\end{longtable}

\end{document}

L’ordre compte. Les quatre marqueurs doivent figurer dans cet ordre, tout en haut du tableau, et tout ce qui est écrit en dessous constitue les vraies données réparties sur les pages. Autrement dit, le corps du tableau commence à la première ligne après \endlastfoot. Bousculez l’ordre et une ligne prévue comme en-tête ressort en première ligne de données. \kill fait exception : il crée une ligne mesurée mais jamais imprimée. Si les titres sont courts mais qu’une valeur très longue n’apparaît qu’en page 100, une ligne \kill d’échantillons de largeur maximale placée en tête donne des colonnes larges dès le départ.

Table widths have changed. Rerun LaTeX. — pourquoi deux compilations

Pour aligner les colonnes sur toutes les pages. longtable compose le tableau page par page, mais la cellule la plus large d’une page n’est connue qu’une fois cette page composée. Si chaque page était composée indépendamment, chacune aurait ses propres largeurs de colonnes. longtable inscrit donc les largeurs mesurées dans le fichier .aux et les relit à la passe suivante comme largeur commune à toutes les pages. D’où ce message à la première compilation :

log
Package longtable Warning: Column widths have changed
(longtable)                in table 1 on input line 24.


Package longtable Warning: Table widths have changed. Rerun LaTeX.

Voici, mesuré, le prix d’un avertissement ignoré. En relevant dans le PDF d’un tableau de trois pages la position du titre de colonne de droite « Amount » : à la première passe il se trouve à x = 320,41pt tandis que les données en dessous sont à x = 488,69pt — titre et chiffres à des endroits différents. Après une seconde passe, le titre se déplace à x = 471,53pt, identique sur les trois pages. La sortie de la première passe est donc un tableau aux colonnes trop étroites, dont les titres ont dérivé vers la gauche. C’est exactement ce que signifie « j’ai compilé une fois et le tableau est bizarre ».

On peut ouvrir ce fichier .aux. Voici ce que laisse un longtable à trois colonnes. \LT@i signifie « le premier longtable de ce document » ; le deuxième devient \LT@ii. Le second argument de chaque entrée est la largeur mesurée d’une colonne, et la passe suivante se sert telle quelle de ces valeurs.

document.aux
\gdef \LT@i {\LT@entry
    {2}{58.6668pt}\LT@entry
    {2}{274.36153pt}\LT@entry
    {1}{47.55566pt}}

La mesure ne se fait pas d’un seul coup mais par blocs, dont la taille est fixée par le compteur LTchunksize (200 lignes par défaut). Si un tableau très long épuise la mémoire de TeX, réduisez-le avec \setcounter{LTchunksize}{10} ; l’augmenter réduit le nombre d’allers-retours par le .aux et peut converger plus vite. En pratique, latexmk vous dispense d’y penser : il relance tant que l’avertissement subsiste.

Légendes et numérotation : LTcapwidth vaut 4 pouces par défaut

longtable n’est pas un flottant et possède pourtant sa propre \caption{…}. Elle incrémente le compteur standard table : la légende est donc numérotée « Tableau N » automatiquement et figure dans \listoftables. Comme la légende fait partie de la mise en page du tableau, la règle est de la placer dans le bloc d’en-tête, avant \endfirsthead, en fermant la ligne par \\, soit \caption{…}\\. Une surprise se cache dans sa largeur : \LTcapwidth vaut par défaut 4 pouces, soit 289,08pt. Comme \textwidth vaut 345pt dans article, la légende est d’origine 56pt plus étroite que le texte. Pour l’aligner sur le bloc de texte, écrivez \setlength{\LTcapwidth}{\textwidth}.

Le reste tient à de petites conventions. Pour supprimer le numéro, utilisez \caption*{…} : ni numéro ni entrée dans la liste des tableaux. Une légende subsidiaire telle que « (continued) » sur les pages suivantes s’écrit avec un argument optionnel vide, \caption[]{…}, pour ne pas être listée deux fois. Et un \label{…} de référence croisée ne doit jamais figurer dans le \endhead répété : la même étiquette serait définie une fois par page. Placez-le dans \endfirsthead, ou sur la première ligne du corps du tableau.

Ce que deviennent les filets booktabs à un saut de page

\toprule, \midrule et \bottomrule fonctionnent tels quels dans un longtable : booktabs a ajouté la compatibilité longtable dans sa version de 2000, et booktabs.sty conserve encore une branche \ifx\longtable\undefined pour cela. Une asymétrie subsiste néanmoins. longtable double automatiquement un \hline au saut de page, traçant un filet au-dessus et un en dessous de la couture, alors que les filets booktabs ne sont pas doublés. Si un filet tombe exactement sur un saut de page, le manuel de booktabs conseille lui-même de corriger à la main, en général en supprimant le filet fautif. La bonne réponse pratique est de concevoir la coupure autrement : mettez les filets dans \endfoot et \endhead pour qu’aucun ne se trouve sur la couture.

Il y a un bonus. L’argument de rognage gauche/droite, qui n’appartient normalement qu’à \cmidrule, agit aussi sur \toprule, \midrule et \bottomrule — mais seulement dans un longtable. Écrivez \toprule(r) et l’extrémité droite rentre ; \midrule(lr) rentre des deux côtés. Cela compile sans erreur sous TeX Live 2024 avec longtable et booktabs chargés ensemble. Revers de la médaille : impossible d’écrire la même chose dans un tabular ordinaire ; l’auteur de booktabs note, à demi sérieux, que si l’on tient absolument aux filets rognés, il n’y a qu’à faire de tous ses tableaux des longtables.

supertabular et xtab : une seule passe, mais des colonnes qui sautent

longtable n’est pas le seul moyen de couper un tableau sur plusieurs pages. supertabular (Johannes Braams et Theo Jurriens) et son descendant xtab (Peter Wilson) adoptent une stratégie tout autre. Là où longtable compose le tableau entier et le confie au découpeur de pages de TeX, ces deux-là mesurent la place restante sur la page et émettent un nouveau tabular qui y tient — donc un tabular indépendant par page. Ils n’ont pas besoin d’aller-retour par le .aux et terminent en une seule compilation.

Le prix se voit directement sur la page. Avec les mêmes 119 lignes et une entrée extrêmement longue placée en ligne 90, les deux se comportent très différemment. Sous supertabular, le titre de colonne « Amount » se trouve à x = 249,16pt aux pages 1 et 2, puis à x = 471,53pt à la page 3, celle qui porte l’entrée longue : on tourne la page et le tableau change de largeur. Les mêmes données sous longtable, après la deuxième compilation, placent le titre à x = 471,53pt sur les trois pages. Compiler deux fois, c’est acheter cette cohérence. La syntaxe diffère aussi : supertabular déclare en-tête et pied hors de l’environnement, via \tablefirsthead, \tablehead, \tabletail et \tablelasttail, avec \topcaption et \bottomcaption pour les légendes. xtab reprend ce principe et ajoute par exemple un nombre minimal de lignes pour éviter une coupure disgracieuse.

Des colonnes X repliables qui traversent aussi les pages : xltabular et ltxtable

longtable utilise la même spécification de colonnes que tabular ; le texte long finit donc dans une colonne p{width} de largeur fixe. Pour une colonne qui s’étend automatiquement sur la largeur restante, il faut la colonne X de tabularx — mais l’environnement tabularx lui-même ne peut pas se couper. Deux ponts comblent l’écart. xltabular (Rolf Niepraschk et Herbert Voß) est un longtable doté de colonnes X : \begin{xltabular}{\linewidth}{l X r} prend une largeur totale et une spécification de colonnes, et les marqueurs de la famille \endfirsthead restent utilisables. Il charge ltablex en interne mais laisse intact l’environnement tabularx existant.

document.tex
\documentclass{article}
\usepackage{xltabular}
\begin{document}

\begin{xltabular}{\linewidth}{l X r}
  \caption{Glossary}\\
  \hline
  Term & Description & Page \\
  \hline
  \endfirsthead
  \hline
  Term & Description & Page \\
  \hline
  \endhead

  longtable  & Breaks across pages; sits in the text flow, not in a float. & 12 \\
  xltabular  & A longtable whose X column takes the leftover width.       & 34 \\
\end{xltabular}

\end{document}

L’autre pont est ltxtable, également de David Carlisle. Ici, le corps du tableau va dans un fichier séparé, rappelé par \LTXtable{\textwidth}{nomdefichier}. Le fichier contient un longtable à colonnes X ; ltxtable exécute une fois le calcul de largeur de tabularx, puis passe le résultat à longtable. Séparer le fichier est fastidieux, mais cela évite que l’expansion répétée de tabularx n’entre en conflit avec l’aller-retour .aux de longtable, d’où une bien meilleure stabilité sur les tableaux longs. Le choix est simple : xltabular pour la commodité, ltxtable quand un grand tableau compliqué se met à faire des siennes. Petit détail : xltabular ne consomme un numéro de table que si vous écrivez effectivement une \caption.