Auf die Frage nach der grundlegendsten Idee von TeX lautet die Antwort weder Schrift noch Mathematik noch der Umbruchalgorithmus – es ist die Box. Alles, was LaTeX auf eine Seite setzt, ist eine Box: ein Rechteck mit Breite, Höhe und Tiefe, durch Leim (glue) mit seinen Nachbarn verbunden und nach dem Zusammenbau nie wieder von innen betrachtet. Daher verhindert \mbox die Trennung eines Wortes, daher meldet TeX eine überlaufende Zeile als Overfull \hbox, und daher trennen sich die Wege von \parbox und minipage genau dort, wo sie es tun. Diese Seite geht die Boxbefehle durch, die tatsächlich getippt werden – \mbox, \makebox, \framebox, \raisebox, \parbox, minipage, \newsavebox – ausgehend von dem einen Gedanken, der unter ihnen allen liegt.
Breite, Höhe und Tiefe: warum eine Box drei Maße hat
Eine Box hat drei Maße, nicht zwei: Breite, Höhe und Tiefe. Die Höhe wird von der Grundlinie nach oben gemessen, die Tiefe von ihr nach unten – eine Box ist also kein Rechteck um die Druckfarbe herum, sondern ein Rechteck, das an der Linie hängt, auf der die Buchstaben stehen. Die drei Werte lassen sich mit \the\wd, \the\ht und \the\dp ausgeben. In 10pt Computer Modern hat das Wort Hx als Box die Tiefe 0.0pt; bei Hxg beträgt sie 1.94444pt, weil das g unter die Grundlinie reicht. Die Breite ist natürlich ebenfalls gewachsen – die Tiefe jedoch aus einem völlig anderen Grund.
Diese eine Tatsache löst ein Rätsel, auf das fast alle stoßen, bevor sie wissen, was eine Box ist: Warum sitzt \fbox{Hx} eng um die Buchstaben, während \fbox{Hxg} durchzuhängen scheint? Weil \fbox die Box rahmt und nicht die Buchstaben – und die Box von Hxg ist 1,94pt tiefer. Stehen mehrere gerahmte Wörter in einer Tabellenzeile nebeneinander, hüpfen die Rahmen im Takt der Unterlängen. Die Abhilfe heißt Stütze (strut): \fbox{\strut Hx} und \fbox{\strut Hxg} haben exakt dieselbe Höhe und Tiefe, denn \strut ist eine unsichtbare Box der Breite null, die das 0,7-Fache des aktuellen \baselineskip über und das 0,3-Fache unter der Grundlinie beansprucht. Ein eigener Abschnitt weiter unten geht darauf ein.
\newsavebox{\probe}
\newcommand{\dims}[1]{\sbox{\probe}{#1}%
\typeout{[#1] w=\the\wd\probe\space h=\the\ht\probe\space d=\the\dp\probe}}
\dims{Hx} % w=12.77782pt h=6.83331pt d=0.0pt <- no descender
\dims{Hxg} % w=17.77783pt h=6.83331pt d=1.94444pt <- the g adds depth
% same words framed: only the second frame sinks below the baseline
\fbox{Hx}\quad\fbox{Hxg}\quad \fbox{\strut Hx}\quad\fbox{\strut Hxg}\mbox: Zeilenumbruch und Trennung unterbinden
\mbox{...} hält seinen Inhalt in einer Zeile und schaltet die Trennung darin ab. Der Grund steht in der Definition selbst: LaTeX deklariert \mbox als nicht mehr als \leavevmode\hbox{#1}. Eine \hbox ist eine bereits zusammengebaute Box, und TeX greift nie in eine fertige Box zurück, um dort nach einer Umbruch- oder Trennstelle zu suchen. \mbox{antidisestablishmentarianism} wird also nicht höflich gebeten, nicht umzubrechen – es kann schlicht nicht umbrechen. Eine Box dieser Art, die ihren Inhalt nur von links nach rechts durchreicht und nie umbricht, heißt in der LaTeX-Terminologie LR-Box (ihr Inneres befindet sich im LR-Modus); \mbox, \makebox, \fbox und \framebox bilden diese Familie und stehen den Absatzboxen \parbox und minipage gegenüber, die eine Breite festlegen und umbrechen. Die gesamte Weltsicht von TeX, dass Satz aus mit Leim verbundenen Boxen besteht, steckt verdichtet in diesem einen Befehl.
Der Preis dafür: Eine unteilbare Box kann zu breit für die Zeile sein, und dann beschwert sich TeX. Die Meldung lohnt eine wörtliche Lektüre: Overfull \hbox (29.62221pt too wide) in paragraph at lines 5--5. Sie nennt eine \hbox und keine Zeile, weil jede Zeile, die TeX erzeugt, selbst eine hbox ist – der Absatzumbruch packt Wörter und dehnbaren Leim in genau eine hbox pro Zeile, das Modell, das Donald Knuth und Michael Plass 1981 als „Breaking paragraphs into lines“ veröffentlichten. Mit der Klassenoption draft setzt LaTeX \overfullrule auf 5pt und druckt neben jeder beanstandeten Zeile einen schwarzen Balken an den Rand; dieser Balken ist selbst nichts als eine gefüllte Box. \mbox gehört zu dem, was wirklich nicht getrennt werden darf – Produktnamen, Telefonnummern, Zahlenwert und Einheit – und nicht als Allheilmittel gegen unschöne Umbrüche.
% never split, never hyphenated
Released for \mbox{Mac OS X} and \mbox{Windows 11}; call \mbox{+81 3-1234-5678}.
% too wide for the measure -> Overfull \hbox (...pt too wide) in the log
\parbox{3.4cm}{aaa \mbox{antidisestablishmentarianism}}
% \documentclass[draft]{article} sets \overfullrule=5pt and marks the line\makebox: Breite und Ausrichtung festlegen – die Box der Breite null, \rlap und \llap
\makebox[width][position]{text} ist ein \mbox, bei dem die Wahl der Breite nicht mehr TeX, sondern der schreibenden Person zufällt. [position] bestimmt, wo der Inhalt innerhalb der geforderten Breite sitzt: l linksbündig, r rechtsbündig, c zentriert (Standard) und s dehnt den Wortzwischenraum, sodass der Inhalt die Breite exakt ausfüllt – \makebox[3cm][s]{a b c d} wird tatsächlich 3cm breit. Jeder andere Buchstabe wird ebenfalls angenommen, führt aber zur Warnung Unexpected alignment und fällt auf c zurück.
Im Breitenargument stehen vier Namen für die natürliche Größe dessen, was gerade in die Box wandert: \width, \height, \depth und \totalheight (Höhe plus Tiefe). Sie werden aus dem Inhalt gesetzt, bevor die Breite ausgewertet wird; \makebox[2\width]{word} misst word also zu 21,4167pt und baut daraus eine Box von 42,8334pt. Das ist die saubere Art, „doppelt so breit wie dies“ zu sagen, ohne festzulegen, was dies sein wird. Dieselben vier Namen funktionieren in den Argumenten von \framebox, \savebox und \raisebox.
Die nützlichste Breite von allen ist 0pt. Eine Box der Breite null wird gesetzt, rückt die aktuelle Position aber nicht weiter und druckt daher über das, was folgt. \makebox[0pt][l]{...} hängt den Inhalt rechts vom aktuellen Punkt aus, \makebox[0pt][r]{...} links davon, [c] legt ihn beidseitig darüber. Für diese beiden gibt es kurze Namen – \rlap und \llap –, und LaTeX definiert sie genau so, als \hbox to 0pt{#1\hss} und \hbox to 0pt{\hss#1}. Überdrucke, hängende Interpunktion, ein Zeichen am Rand und die meisten selbstgebauten Durchstreichungsmakros sind alle dieser eine Trick.
\makebox[3cm][l]{left}|\makebox[3cm][r]{right}|
\makebox[3cm][s]{a b c d}| % interword glue stretched to exactly 3cm
\makebox[2\width]{word}| % twice the natural width of "word"
% zero width: the slash overprints the space that follows the X
X\rlap{/}\quad Y % identical to X\makebox[0pt][l]{/}\quad Y\fbox und \framebox im Vergleich – die zwei Längen eines Rahmens
Der Unterschied zwischen \fbox{text} und \framebox[width][position]{text} ist genau der Unterschied zwischen \mbox und \makebox: \fbox rahmt den Inhalt in seiner natürlichen Breite, \framebox rahmt ihn in einer selbst gewählten Breite, mit denselben Positionen l/c/r/s. Beide ziehen an allen vier Seiten der Box eine Linie, und das Aussehen bestimmen zwei Längen: die Linienstärke \fboxrule beträgt 0,4pt, der Abstand zwischen Linie und Inhalt \fboxsep 3pt. Die Rechnung geht auf: Hx ist 12,77782pt breit, \fbox{Hx} misst 19,5778pt – die Differenz ist genau das Doppelte von 3,4pt. Mit \setlength{\fboxsep}{0pt} legt sich der Rahmen direkt an die Buchstaben.
\fbox ist eine LR-Box und rahmt daher genau eine Zeile. Um einen Absatz zu rahmen, rahmt man eine Absatzbox – \fbox{\parbox{6cm}{...}}. Die äußere Box kümmert sich nicht darum, was in ihr steckt, sondern nur darum, wie groß es ist. Genau diese Kombinierbarkeit macht das Boxmodell aus, und sie erklärt zugleich, warum ein Rahmen um eine \parbox das Unterlängenproblem aus dem vorigen Abschnitt erbt; ein \strut am Anfang und am Ende des gerahmten Textes hält einen Stapel solcher Rahmen auf gleicher Höhe. Sobald abgerundete Ecken, eine Hintergrundfarbe oder ein über Seiten umbrechender Rahmen gefragt sind, beginnt das Revier von Paketen wie framed und tcolorbox – behandelt auf der Seite über Rahmen.
\setlength{\fboxrule}{1pt} % default 0.4pt
\setlength{\fboxsep}{6pt} % default 3pt
\fbox{one line}\quad\framebox[4cm][r]{4cm wide, flush right}
% frame a whole paragraph: put a paragraph box inside the frame
\fbox{\parbox{6cm}{\strut A framed paragraph. The frame follows the box,
and the struts keep its height independent of ascenders and descenders.\strut}}Der Unterschied zwischen \parbox und minipage
Beide legen eine Breite fest und lassen den Text darin umbrechen. Der Unterschied liegt nicht, wie oft behauptet, darin, dass eine \parbox nur einen Absatz fasse. Sie fasst beliebig viele, und Listen ebenso – \parbox{4cm}{First.\par Second.} liefert tatsächlich zwei Absätze. Der wirkliche Unterschied ist, dass minipage eine Umgebung und \parbox ein Befehl ist; davon hängt ab, was im Inneren zulässig ist. Sonst stimmen die Signaturen überein: \parbox[position][height][inner-pos]{width}{text} und \begin{minipage}[position][height][inner-pos]{width}. Beide setzen \parindent und \parskip auf null und \linewidth auf die Boxbreite – deshalb tut \includegraphics[width=\linewidth]{...} in beiden das Richtige.
[position] bestimmt, wie die Box auf die umgebende Zeile trifft, und wird am häufigsten falsch verstanden. [t] richtet nicht die Oberkante der Box aus: Es legt die Grundlinie der ersten Boxzeile auf die umgebende Grundlinie. Misst man eine dreizeilige \parbox[t], beträgt ihre Höhe 4,30554pt – die Höhe eines kleinen o, nicht die der Box –, ihre Tiefe dagegen 24pt, also zwei volle Zeilen unterhalb der Grundlinie. [b] tut dasselbe spiegelbildlich mit der letzten Zeile, und das voreingestellte [c] zentriert die Box auf der Zeile. Zwei [t]-minipages richten sich also an ihren ersten Grundlinien aus; beginnt eine davon mit einer Abbildung oder einer größeren Schrift, bleiben die Oberkanten ungleich. Abhilfe schafft ein \strut am Anfang jeder Box oder ein \raisebox auf einer von beiden. Die vierargumentige Form \parbox[position][height][inner-pos]{width}{text} erzwingt zusätzlich eine Höhe, und [inner-pos] bestimmt dann, ob der Inhalt oben (t), mittig (c) oder unten (b) in dieser Höhe sitzt oder mit s über sie gedehnt wird.
Wirklich trennen sich ihre Wege bei der Frage, was hineindarf. Der Text einer \parbox wird als Makroargument gelesen, mit bereits festgelegten Kategoriecodes; \parbox{5cm}{\begin{verbatim}...\end{verbatim}} scheitert daher rundheraus mit ! Argument of \@xverbatim has an extra }. – dasselbe verbatim funktioniert innerhalb einer minipage. Fußnoten sind schlimmer als ein Fehler: Eine \footnote in einer \parbox druckt ihre Marke und verliert den Fußnotentext vollständig, weil das Insert in der Box gefangen bleibt und die Seite nie erreicht. Eine minipage behandelt den Fall bewusst und setzt die Note direkt unter sich, mit einem kursiven Kleinbuchstaben aus dem eigenen Zähler mpfootnote. Gleitobjekte sind in beiden tabu: Ein figure in einer minipage bricht mit ! LaTeX Error: Not in outer par mode. ab. Und keine von beiden lässt sich über eine Seitengrenze trennen, denn eine Box wird definitionsgemäß als Ganzes platziert.
| Inhalt | \parbox | minipage |
|---|---|---|
\par | mehrere Absätze möglich | mehrere Absätze möglich |
itemize | funktioniert | funktioniert (Listentiefe wird zurückgesetzt) |
verbatim | ! Argument of \@xverbatim has an extra }. | funktioniert |
\footnote | Marke erscheint, Text geht verloren | erscheint unter der Box, kursiver Buchstabe |
figure | nicht zulässig | ! LaTeX Error: Not in outer par mode. |
\parindent | auf 0 zurückgesetzt | auf 0 zurückgesetzt |
Die häufigste Aufgabe einer minipage sind zwei nebeneinanderstehende Spalten: zwei Boxen zu je etwa 0,48 von \textwidth, dazwischen ein \hfill. Die Summe muss unter eins bleiben, sonst passt die zweite nicht mehr. Und hier lauert die Falle, die jeden einmal einen halben Tag kostet: Der Zeilenumbruch in der Quelle zwischen \end{minipage} und \begin{minipage} ist ein gewöhnliches Leerzeichen, und so werden die beiden Boxen um einen nie getippten Wortzwischenraum auseinandergeschoben. Ein % am Zeilenende lässt ihn verschwinden. Sobald die Spalten in der Höhe zueinander passen sollen oder Text um die Box fließen soll, geht es auf der Seite zu Gleitobjekten und Platzierung weiter.
\noindent
\begin{minipage}[t]{0.48\textwidth}
\strut Left column. Several paragraphs, lists and a local footnote
are all fine here.\footnote{Printed under this box, marked a, b, \dots}
\end{minipage}\hfill% <- the % kills the newline; without it the boxes drift apart
\begin{minipage}[t]{0.48\textwidth}
\strut Right column. [t] aligns the FIRST BASELINES, not the tops --
the struts are what make the tops line up as well.
\end{minipage}\raisebox: eine Box verschieben und ihre Maße vortäuschen
\raisebox{lift}{text} hebt seinen Inhalt um lift an, bei negativem Wert senkt es ihn ab; es ist das übliche Werkzeug, um zwei unterschiedlich große Elemente auf einer Grundlinie auszurichten. Interessant sind die beiden optionalen Argumente: \raisebox{lift}[height][depth]{text} lässt LaTeX diese Höhe und Tiefe nach außen melden, unabhängig davon, was tatsächlich gezeichnet wird. \raisebox{0pt}[0pt][0pt]{\Huge Ag} belegt weiterhin seine vollen 28,66008pt Breite, misst aber 0pt hoch und 0pt tief (in Wahrheit 16,99782pt und 4,83937pt), sodass der Zeilenabstand ringsum so berechnet wird, als wäre dort nichts. So landet ein Schmuckzeichen oder eine überdimensionierte Glyphe im Fließtext, ohne eine Lücke aufzureißen; auch die vier Kurzformen \width, \height, \depth und \totalheight stehen hier zur Verfügung. Widerspricht die Deklaration der Druckfarbe, kommt es natürlich zu Überlappungen – Maße also nur dort vortäuschen, wo die Überlappung beabsichtigt ist.
\rule und die Stütze (strut): eine unsichtbare Box, die Höhe reserviert
\rule[lift]{width}{height} zeichnet ein ausgefülltes schwarzes Rechteck – fast der einzige LaTeX-Befehl, der Druckfarbe in Gestalt einer Box selbst auf die Seite bringt. \rule{0.5\linewidth}{0.4pt} ergibt eine dünne waagerechte Linie von halber Zeilenbreite. Das optionale [lift] verschiebt das Rechteck gegenüber der Grundlinie, ohne seine Größe zu ändern: \rule[-2pt]{10pt}{8pt} misst 10pt breit, 6pt hoch und 2pt tief – von den 8pt des Rechtecks hängen 2pt unter der Zeile.
Setzt man die Breite auf null, druckt die Linie nichts mehr, reserviert aber weiterhin Platz – das ist eine Stütze (strut). \rule{0pt}{2.6ex} ist unsichtbar, 0pt breit und 11,19443pt hoch; am Anfang einer Tabellenzeile eingefügt, garantiert es dieser Zeile mindestens diese Höhe. Das eigene \strut von LaTeX ist eine fertige Variante nach dem aktuellen Zeilenvorschub: Bei einem \baselineskip von 12pt misst es 8,39996pt Höhe und 3,60004pt Tiefe – eine Aufteilung der Zeile in 0,7 und 0,3. Genau deshalb kamen \fbox{\strut Hx} und \fbox{\strut Hxg} identisch heraus: Die Stütze ist höher und tiefer als beide Wörter, sodass die Unterlänge die Boxmaße nicht mehr bestimmt. Das ist die übliche Abhilfe, wenn Text an einer \hline klebt, und zugleich das Mittel, um eine Reihe von Boxen im gleichen vertikalen Rhythmus zu halten.
% a centred horizontal rule
\noindent\hfil\rule{0.5\linewidth}{0.4pt}\hfil
% a strut forces a taller, roomier table row
% (\strut is the ready-made one, sized to the current \baselineskip)
\begin{tabular}{|l|}
\hline
\rule{0pt}{2.6ex}Tall, uncramped row \\
\hline
\strut Same idea, sized to the current leading \\
\hline
\end{tabular}
% put two differently sized boxes on one baseline
big \raisebox{-0.4ex}{\Huge A} smallBoxen speichern mit \newsavebox, \sbox und \usebox
Material, das mehr als einmal vorkommt, lässt sich einmal setzen und danach abspielen. \newsavebox{\name} reserviert ein Boxregister, \sbox{\name}{text} füllt es – oder \savebox{\name}[width][position]{text}, wenn die Form im Stil von \makebox gewünscht ist –, und \usebox{\name} gibt es aus. Gesetzt wird der Inhalt tatsächlich nur im Moment des \sbox und danach nie wieder; eine lange Tabelle oder eine verwickelte Abbildung an drei Stellen kostet also einen einzigen Satzdurchgang, und alle drei Kopien stimmen bis auf den Punkt überein.
Boxregister sind eine endliche Ressource, und rund zwei Jahrzehnte lang waren sie eine knappe. Das ursprüngliche TeX besaß genau 256 davon, nummeriert von 0 bis 255, und ein Dokument mit zu vielen Zuweisungen blieb mit ! No room for a new \box stehen. eTeX hob die Grenze auf 32768, LuaTeX auf 65536 – deshalb stößt heute niemand mehr daran. LaTeX bestimmt die Grenze beim Bau des Formats anhand der Engine; sein internes \e@alloc@top beträgt entsprechend 255, 32767 oder 65535. Zwei Hinweise zur Schnittstelle: Eine Speicherbox ist eine LR-Box, mehrzeiliger Inhalt wandert also zuerst in eine \parbox oder minipage, und für Inhalte mit verbatim ist die Umgebungsform \begin{lrbox}{\name} … \end{lrbox} zuständig. Ältere Darstellungen warnen, \savebox sei fragil; im heutigen LaTeX stimmt das nicht – \mbox, \makebox, \fbox, \parbox, \raisebox, \sbox und \savebox sind allesamt als robust deklariert.
Die Gefährten von \usebox heißen \settowidth{\len}{text}, \settoheight und \settodepth. Sie setzen den Text unsichtbar und legen eine der Abmessungen des Ergebnisses in einer Länge ab. Es gibt sie, damit sich etwas genau in der Größe von etwas anderem zeichnen lässt: die Breite einer Unterschriftszeile messen und dann mit \rule unterstreichen.
\newsavebox{\mylogo}
\sbox{\mylogo}{\fbox{\textbf{Draft}}} % typeset once, here
Header: \usebox{\mylogo} \dots\ Footer: \usebox{\mylogo}
% verbatim inside a save box needs the environment form
\newsavebox{\snippet}
\begin{lrbox}{\snippet}
\begin{minipage}{6cm}\begin{verbatim}int main(void) { }\end{verbatim}\end{minipage}
\end{lrbox}
\usebox{\snippet}
% measure a box into a length, then rule exactly that wide
\newlength{\siglen}
\settowidth{\siglen}{Signature}
Signature\par\rule{\siglen}{0.4pt}Welcher Boxbefehl wann
| Befehl | Art | Einsatz |
|---|---|---|
\mbox | LR | diese Wortgruppe darf nie getrennt werden |
\makebox | LR | die Breite selbst wählen oder mit [0pt] überdrucken |
\rlap | LR | Kurzform für \makebox[0pt][l] (\llap hängt nach links) |
\fbox | LR | ein Rahmen in natürlicher Breite |
\framebox | LR | ein Rahmen in gewählter Breite (\fboxsep, \fboxrule) |
\parbox | Absatz | Text in fester Breite umbrechen, etwa in einer Tabellenzelle |
minipage | Absatz | verbatim, Fußnoten oder nebeneinanderstehende Spalten |
\raisebox | Transformation | nach oben/unten verschieben oder Höhe und Tiefe null melden |
\rule | gefüllte Box | eine Linie ziehen; Breite null ergibt eine unsichtbare Stütze |
\strut | Stütze | Zeilen- oder Zellenhöhen angleichen |
\usebox | Speicher | eine mit \newsavebox + \sbox gebaute Box ausgeben |
\settowidth | Messung | die Breite (auch \settoheight, \settodepth) in einer Länge ablegen |