Inhalts-, Abbildungs- und Tabellenverzeichnis (tocloft)

Das Inhaltsverzeichnis auf Seite eins des PDFs stammt nicht aus dem Lauf, der dieses PDF erzeugt hat. \tableofcontents, \listoffigures und \listoftables lesen jeweils eine kleine Datei, die der vorherige LaTeX-Lauf hinterlassen hat: .toc, .lof und .lot. Und diese Dateien sind keine Textzwischenspeicher, sondern kurze Programme mit einer Zeile pro Eintrag, die der nächste Lauf ausführt. Aus dieser einen Tatsache folgt fast alles, was an den drei Befehlen verwirrt: warum ein frisches Dokument nichts anzeigt, warum die Seitenzahlen beim ersten Mal danebenliegen, warum eine Fußnote in einer Abschnittsüberschrift erst beim zweiten Lauf explodiert und nicht beim ersten – und warum LaTeX kein einziges Mal warnt, dass das gedruckte Verzeichnis falsch ist.

Was in einer .toc-, .lof- oder .lot-Datei tatsächlich steht

Ein Befehl pro Eintrag, und zwar stets \contentsline. Die drei Verzeichnisse teilen denselben Mechanismus: \tableofcontents gehört zur .toc, \listoffigures zur .lof, \listoftables zur .lot, und jede dieser Dateien trägt den Namen der Hauptdatei. \contentsline nimmt vier Argumente – die Art des Eintrags, den zu druckenden Text, die Seitenzahl und ein Sprungziel. Das vierte bleibt in reinem LaTeX leer; mit hyperref steht dort ein PDF-Ziel wie section.1.1. Eine .toc ist also kein Entwurf des Verzeichnisses, sondern eine Folge von Anweisungen für den nächsten Lauf.

mydoc.toc
% one \contentsline per entry: unit, text, page, link target
\contentsline {chapter}{\numberline {1}Body}{5}{chapter.1}%
\contentsline {section}{\numberline {1.1}Short form}{5}{section.1.1}%
% and in mydoc.lof, written by \caption inside a figure:
\addvspace {10\p@ }
\contentsline {figure}{\numberline {1.1}{\ignorespaces Short caption}}{5}{figure.1.1}%

Diese Zeilen wandern allerdings nicht direkt in die Verzeichnisdatei. Sie sammeln sich zunächst in der .aux-Datei als \@writefile{toc}{...}, und erst wenn LaTeX die .aux bei \end{document} schließt und erneut einliest, fließen sie in die .toc. Dieser Umweg hat zwei praktische Folgen. Erstens öffnet \tableofcontents selbst den Schreibkanal: Fehlt der Befehl im Dokument, entsteht überhaupt keine .toc-Datei – die Einträge bleiben einfach in der .aux stehen. Zweitens darf \tableofcontents überall stehen, weil das Schreiben ganz am Ende in einem Zug geschieht. Auf der letzten Seite platziert liefert es weiterhin ein vollständiges Inhaltsverzeichnis samt aller Überschriften, die darüber stehen.

BefehlGeschriebene DateiHerkunft der Einträge
\tableofcontents.tocÜberschriften von \chapter bis \subparagraph sowie \addcontentsline{toc}{...}
\listoffigures.lof\caption innerhalb einer figure, bei Bedarf das kurze optionale Argument
\listoftables.lot\caption innerhalb einer table, mechanisch identisch zur .lof
\addcontentslinedie angegebene Endungeine handgeschriebene Zeile; die Seitenzahl ist \thepage in diesem Moment
\addtocontentsdie angegebene EndungMaterial statt eines Eintrags: Abstände, Formatierungsbefehle

Warum das Verzeichnis leer bleibt – und warum LaTeX nicht warnt

Weil es beim ersten Lauf noch keine .toc zu lesen gibt. Im Protokoll steht die einzelne Zeile No file mydoc.toc., und \tableofcontents setzt lediglich seine Überschrift und geht weiter. Geschrieben wird die Datei am Ende dieses Laufs, also erscheinen die Einträge erst im zweiten auf dem Papier. Und im zweiten Lauf belegt das Verzeichnis selbst Seiten, wodurch sich alle nachfolgenden Seitenzahlen verschieben – gelegentlich braucht es einen dritten Lauf, bis sich alles einpendelt. Ein Lauf speichert die Information, ein anderer holt sie ab; genau dieses zweistufige Verfahren steckt auch hinter \label und \ref, das die Seite zu Querverweisen ausführlich behandelt.

Und hier die Hälfte, die selten erwähnt wird: LaTeX warnt kein einziges Mal vor dieser Verzögerung. Eine undefinierte Referenz erzeugt LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right., aber nur, weil Marken mit ihren früheren Werten in der .aux verglichen werden. Für das Verzeichnis gibt es keinen solchen Vergleich. Widersprechen sich die gedruckte Tabelle und die eben geschriebene .toc, schweigt das Protokoll vollständig – im Protokoll eines Laufs, der ein leeres Inhaltsverzeichnis ausgegeben hat, findet sich keine einzige Warnung. Genau deshalb übernimmt besser ein Werkzeug wie latexmk das Zählen der Durchläufe: Es wiederholt, bis sich die .toc nicht mehr ändert.

Dieselbe Stille zeigt sich in einer unangenehmeren Form. Wird ein Manuskript von report auf article umgestellt, enthält die alte .toc weiterhin Zeilen der Form \contentsline {chapter}{...}. article definiert kein \l@chapter, und da \contentsline lediglich \csname l@chapter\endcsname aufruft, wird ein undefinierter Name stillschweigend zu \relax – Titel und Seitenzahl landen also als gewöhnlicher Fließtext im Verzeichnis. Kein Fehler, keine Warnung, nur eine rätselhafte Zeile wie „1 Alpha2“. Sieht das Verzeichnis nach einem Wechsel der Klasse oder der Verzeichnisstruktur beschädigt aus, führt der kürzeste Weg über das Löschen von .toc und .aux und einen erneuten Lauf.

Es gibt nur ein tocdepth – die Einstellung, die das Abbildungsverzeichnis leert

tocdepth ist ein Zähler, der die tiefste im Verzeichnis gedruckte Ebene benennt: \setcounter{tocdepth}{1} endet bei Abschnitten, {2} reicht bis zu Unterabschnitten. Die Vorgaben sind 3 in article und 2 in book und report. Es ist jedoch kein Zähler allein für das Inhaltsverzeichnis. In article.cls und book.cls steht \l@figure als \@dottedtocline{1}{1.5em}{2.3em} – jeder Eintrag des Abbildungsverzeichnisses wird also auf Ebene 1 gesetzt, und \l@table ist ein Alias dazu. Und \@dottedtocline vergleicht gegen das eine, von allen drei Listen geteilte tocdepth.

Die Folge ist unfreundlich. Wer in einem book beschließt, das Verzeichnis solle nur Kapitel führen, und \setcounter{tocdepth}{0} schreibt, leert damit Abbildungs- und Tabellenverzeichnis. Die .lof enthält weiterhin jeden Eintrag, aber Ebene 1 übersteigt ein tocdepth von 0, und so wird keine einzige Zeile gedruckt. Ein Fehler erscheint nicht. Die Abhilfe ist klein: \listoffigures in eine Gruppe einschließen und tocdepth darin anheben. Dass tocdepth erst beim Zurücklesen filtert – weshalb eine Änderung der Tiefe die .toc nie neu erzeugen muss und nur einen zusätzlichen Lauf kostet – behandelt die Seite zur Dokumentstruktur.

latex
\setcounter{tocdepth}{0}     % contents: chapters only

% ... but this alone would print an EMPTY list of figures.
% Raise the depth for the float lists only:
\begingroup
  \setcounter{tocdepth}{1}
  \listoffigures
  \listoftables
\endgroup

% Because the .toc is a program, a depth change can also be
% injected into the middle of it, taking effect from here on:
\addtocontents{toc}{\protect\setcounter{tocdepth}{1}}

Aufgezeichnet wird der kurze Titel: das optionale Argument von \section[...]

Der kurze Titel in eckigen Klammern gelangt in die .toc; der lange in geschweiften Klammern erscheint nur im Text. \section[Kurzform]{Ein langer Titel, der sich über die Seite zieht} lässt die Überschrift auf der Seite lang, während Verzeichnis und Kolumnentitel die Kurzform übernehmen. \caption[Kurze Beschriftung]{Eine lange Erläuterung} folgt derselben Regel, und in .lof und .lot landet die kurze Fassung – die Seite zu Bildunterschriften behandelt diese Seite der Sache genauer. Wichtig ist hier: Dieses optionale Argument ist kein Luxus zur Verschönerung.

Eine Überschrift wird in die .toc hinausgeschrieben – in eine Datei gegossen und beim nächsten Lauf zurückgelesen. Steckt darin ein zerbrechlicher Befehl, etwa \section{Titel mit Anmerkung\footnote{Anmerkung}}, läuft die erste Kompilierung klaglos durch, während die zweite genau beim Zurücklesen zusammenbricht. Runaway argument?, dann ! Paragraph ended before \contentsline was complete., dann ! Argument of \@sect has an extra }. – Meldungen, die mit einer Überschrift nichts zu tun zu haben scheinen, obwohl der Übeltäter die Fußnote in der eben geschriebenen .toc ist. Der Fehler kommt aus demselben Grund einen Lauf zu spät wie das Verzeichnis. Das Rezept ist das optionale Argument: \section[Titel mit Anmerkung]{Titel mit Anmerkung\footnote{Anmerkung}} hält die Fußnote aus der .toc heraus, und nichts bricht mehr.

latex
% the bracketed form is what lands in .toc, .lof and the running head
\section[Short form]{A long section title that would wrap in the contents}

% fragile material belongs in the braces only, never in the file
\section[Title with a note]{Title with a note\footnote{note text}}

\begin{figure}
  \includegraphics{plot}
  \caption[Short caption]{A long caption explaining every detail}
\end{figure}

Derselbe Umstand – dass eine Überschrift an drei Stellen verwendet wird – taucht in anderer Gestalt wieder auf, sobald hyperref geladen ist. Der Titel wird für die PDF-Lesezeichen weiterverwendet, und ein Lesezeichen ist reiner Text, verträgt also keine Formeln. \section{Eigenschaften von $\mathcal{A}$} liefert Package hyperref Warning: Token not allowed in a PDF string (Unicode), und die Formel fällt stillschweigend weg. Der Ausweg heißt \texorpdfstring{$\mathcal{A}$}{A}: eine Fassung für den Satz, eine für die Zeichenkette – behandelt auf der Seite zu hyperref.

Eine Sternüberschrift ins Verzeichnis bringen: addcontentsline und sein Platz

\addcontentsline{toc}{section}{Einleitung} gehört in die Zeile direkt nach der Überschrift. Ein \section* oder \chapter* trägt keine Nummer und schreibt nichts in die .toc; soll es dort erscheinen, muss die Zeile von Hand eingefügt werden. Alle drei Argumente sind erforderlich.

  • ext — die Endung der Ziel-Hilfsdatei: toc für das Inhaltsverzeichnis, lof für Abbildungen, lot für Tabellen.
  • unit — die Art des Eintrags. Für toc etwa part, chapter, section, subsection; Format und Einzug dieser Ebene werden übernommen. Für lof gilt figure, für lot table.
  • text — der aufzuführende Text. Ein vorangestelltes \protect\numberline{} richtet den Titel wie nummerierte Einträge aus; vor jeden zerbrechlichen Befehl gehört \protect.

Die Platzierung entscheidet über das Ergebnis. In der Definition in latex.ltx schreibt \addcontentsline lediglich \contentsline{unit}{text}{\thepage}{} heraus – es brennt also die Seitenzahl ein, die im Augenblick der Ausführung gilt. Da \chapter* eine neue Seite beginnt, hält die Zeile, unachtsam vor das \chapter* gesetzt, die vorige Seitenzahl fest. Der Versuch ist eindeutig: Der davor platzierte Eintrag zeigte auf Seite 2, der unmittelbar danach platzierte auf Seite 3. Die Lesenden schlagen die Seite auf und finden dort kein Kapitel. Die Seitenzahl liefert LaTeX selbst; in text gehört sie nie.

latex
% right: the line runs after the page break that \chapter* causes
\chapter*{Acknowledgements}
\addcontentsline{toc}{chapter}{Acknowledgements}

\section*{Introduction}
\addcontentsline{toc}{section}{Introduction}

% \addtocontents injects material, not an entry
\addtocontents{lof}{\protect\vspace{2ex}}

Der Gefährte \addtocontents{ext}{text} fügt Material statt einer Zeile ein. Er nimmt nur die Zielendung und den zu schreibenden Inhalt und hängt keine Seitenzahl an. Ein Blick in eine .lof fördert die Zeile \addvspace {10\p@ } zutage – auf genau diesem Weg fügt LaTeX bei jedem Kapitelwechsel selbst Abstand ein. Kurz: Eine Zeile mit Seitenzahl läuft über \addcontentsline, Abstände und Formatierung über \addtocontents. Beide schreiben für den nächsten Lauf, weshalb ein zerbrechlicher Befehl wie \vspace ein \protect braucht.

Die Verzeichnisse selbst ins Inhaltsverzeichnis: tocbibind

Eine Zeile, \usepackage{tocbibind}, und Abbildungsverzeichnis, Tabellenverzeichnis, Literaturverzeichnis und Index erscheinen von selbst im Inhaltsverzeichnis. Diese Überschriften tragen keine Nummer – in article \section*, in book und report \chapter* – und tauchen daher sonst nie auf. Man kann stattdessen \addcontentsline-Aufrufe von Hand setzen, doch bei einem mehrseitigen Literaturverzeichnis oder Index gerät die Platzierung leicht daneben; das Paket ist die sicherere Wahl.

Standardmäßig führt es auch das Inhaltsverzeichnis im Inhaltsverzeichnis auf, weshalb nottoc die Option ist, nach der die meisten zuerst suchen. Zum Ausschließen dienen nottoc, notlof, notlot, notbib und notindex. Umgekehrt setzen numbib und numindex Literaturverzeichnis und Index als nummerierte Kapitel oder Abschnitte statt als unnummerierte Überschriften. Das in TeX Live 2024 enthaltene tocbibind ist v1.5k von 2010, von Peter Wilson – demselben Autor wie tocloft.

latex
% list everything except the contents itself
\usepackage[nottoc]{tocbibind}

% the manual equivalent, one line per list
\cleardoublepage
\addcontentsline{toc}{chapter}{\listfigurename}
\listoffigures

Einzüge, Schriften und Punktführer mit tocloft umformen

Mit \usepackage{tocloft} erhält jede Ebene eigenen Einzug, eigene Nummernbreite, Schrift und Punktführung. Die Befehlsnamen sind systematisch: ein Präfix für die Ebene (toc für part, chap für chapter, sec für section, subsec für subsection, fig für Abbildungen, tab für Tabellen) plus eine Rolle. Einzug und Nummernbreite werden gemeinsam gesetzt, etwa \cftsetindents{section}{1.5em}{2.5em}; kollidieren breiter werdende Nummern mit dem Titel, vergrößert man das dritte Argument. Die Schriften sind für den Eintragstitel (\cftsecfont) und seine Seitenzahl (\cftsecpagefont) getrennt.

Der Punktführer verbirgt einen Kniff, den die Namen nicht verraten. Der Punktabstand ist die Länge \cftdotsep (Vorgabe 4.5) – kleiner rückt die Punkte zusammen, größer zieht sie auseinander. Und \cftnodots, womit sich ein Führer entfernen lässt, ist kein Schalter: In tocloft.sty ist es schlicht die Zahl 5000, ein Abstand, so breit, dass kein einziger Punkt in die Zeile passt. Derselbe Kniff erklärt eine Kleinigkeit, die man tausendmal gesehen und nie bemerkt hat: \cftpartdotsep und \cftchapdotsep sind auf \cftnodots voreingestellt, weshalb in einem Standardinhaltsverzeichnis allein die Teil- und Kapitelzeilen ohne Punkte auskommen.

BefehlSteuertSchreibweise
\cftsetindentsEinzug und Nummernbreite einer Ebene\cftsetindents{section}{1.5em}{2.5em}
\cftsecfontSchrift des Titels eines Abschnittseintrags\renewcommand{\cftsecfont}{\bfseries}
\cftsecpagefontSchrift der Seitenzahl eines Abschnittseintragsfür Kapitel \cftchappagefont
\cftsecleaderPunktführer eines Abschnittseintragsdas enthaltene \cftdotfill{\cftdotsep} ersetzen
\cftdotsepPunktabstand; Vorgabe 4.5, kleiner heißt dichter\renewcommand{\cftdotsep}{2}
\cftnodotsDie Zahl 5000 – ein Abstand, in den kein Punkt passtzum vollständigen Entfernen eines Führers
\cftloftitlefontSchrift der Überschrift des Abbildungsverzeichnissesfür das Inhaltsverzeichnis \cfttoctitlefont
latex
\usepackage{tocloft}
\renewcommand{\cftsecfont}{\bfseries}
\renewcommand{\cftsecpagefont}{\bfseries}
\renewcommand{\cftsecleader}{\bfseries\cftdotfill{\cftdotsep}}
\renewcommand{\cftdotsep}{2}          % tighter dots
\cftsetindents{section}{1.5em}{2.5em} % indent, number width

% drop the leader on section lines altogether
\renewcommand{\cftsecleader}{\cftdotfill{\cftnodots}}

Wenn tocloft nicht mehr reicht: titletoc und etoc

Während tocloft Maße und Schriften vorhandener Zeilen anpasst, schreiben titletoc und etoc die Struktur einer Zeile neu. Herzstück von titletoc (von Javier Bezos, im selben Bündel wie titlesec) ist \titlecontents: Ebene für Ebene definiert es das Material vor der Zeile, den Satz der Nummer, den Titel, die Füllung bis zur Seitenzahl und das, was der Zeile folgt. Genügen schlichte Punkte, gibt es die Kurzform \dottedcontents. Darüber hinaus erlauben \startcontents, \printcontents, \stopcontents und \resumecontents ein Teilinhaltsverzeichnis für ein einzelnes Kapitel an dessen Anfang. In einem Dokument, dessen Überschriften bereits von titlesec geformt sind, lässt sich das Verzeichnis in derselben Sprache formen.

etoc (von Jean-François Burnol) geht weiter und gestaltet das Verzeichnis vollständig neu, über ein zweischichtiges Gerüst aus „Zeilenstilen“ und „globalen Stilen“. Kernstück ist \localtableofcontents, das aus derselben .toc beliebig oft ein kapitelweises Teilverzeichnis zieht; auf dieser Ebene rückt selbst ein baumförmiges Inhaltsverzeichnis in Reichweite. Als Entscheidungsweg bewähren sich drei Schritte: Maße und Schriften mit tocloft einrichten; zu titletoc wechseln, sobald sich der Aufbau einer Zeile ändern soll; zu etoc greifen, wenn die Gestaltung des Verzeichnisses selbst übernommen werden soll.