Klassenoptionen und eigene Klassen

\documentclass[unknownoption]{article} übersetzt anstandslos. Eine falsch geschriebene Klassenoption ist kein Fehler: LaTeX vergräbt LaTeX Warning: Unused global option(s): im Log und liefert trotzdem ein PDF, sodass es kaum auffällt. Schreibt man stattdessen \usepackage[unknownoption]{color}, bricht der Lauf sofort ab. Diese Asymmetrie ist keine Laune, sondern folgt einem bewussten Entwurf: Eine unbekannte Option hat in einer Klasse ein anderes Standardziel als in einem Paket. Von diesem Mechanismus ausgehend entwickelt diese Seite \DeclareOption und \ProcessOptions, das neuere \DeclareKeys und schließlich \LoadClass, mit dem die eigene Klasse auf einer vorhandenen aufsetzt.

Warum eine falsch geschriebene Klassenoption den Lauf nicht stoppt

Die Antwort steht ausdrücklich im offiziellen clsguide. Enthält eine Klassendatei kein \DeclareOption*, werden alle von ihr nicht deklarierten Optionen stillschweigend an sämtliche Pakete weitergereicht. Enthält eine Paketdatei kein \DeclareOption*, erzeugt jede nicht deklarierte Option einen Fehler. Eine Klassenoption wird also weitergetragen, weil sie noch jemand brauchen könnte; erst wenn sie bis \begin{document} niemand beansprucht hat, meldet LaTeX LaTeX Warning: Unused global option(s): und listet die übrigen Namen in eckigen Klammern. Eine Paketoption hat dagegen kein weiteres Ziel, sodass ein unbekannter Name sofort zu ! LaTeX Error: Unknown option 'unknownoption' for package 'color'. wird.

Der Entwurf ist sinnvoll: Optionen, die die Klasse selbst nicht kennt, die aber ein später geladenes Paket beansprucht – globale Optionen wie bei \documentclass[dvipsnames]{article} –, werden täglich verwendet. Der Preis dafür: Tippfehler bleiben stumm. Zwei Gewohnheiten zahlen sich in der Praxis aus. Erstens: nach jedem Lauf im Log nach Unused global option suchen. Zweitens: \listfiles an den Anfang der Präambel setzen, damit am Ende des Logs alle geladenen Dateien mit Version stehen. Übrigens schickt ein \OptionNotUsed im Code einer Option diese absichtlich auf dieselbe Liste der unbenutzten Optionen.

Der Unterschied zwischen Klasse (.cls) und Paket (.sty)

Der clsguide formuliert den Test in einer Zeile: Ließen sich die Befehle mit jeder Dokumentklasse verwenden, mache daraus ein Paket; sonst eine Klasse. Eine Klasse definiert die Dokumentart selbst und wird mit \documentclass genau einmal geladen. Ein Paket wird mit \usepackage geladen, in beliebiger Zahl, und ergänzt Funktionen unabhängig von der Dokumentart. Das Beispiel des Handbuchs macht es greifbar: Eine Firmenklasse zum Setzen von Briefen auf eigenem Briefpapier baut auf letter auf, taugt aber für keine andere Klasse – also ownlet.cls; das Paket graphics zum Einbinden von Bildern funktioniert mit jeder Klasse – also graphics.sty.

Auch Klassen gibt es in zwei Arten: die freistehenden wie article, report und letter und jene, die Erweiterungen oder Varianten einer anderen Klasse sind – der clsguide nennt als Beispiel proc, das auf article aufbaut. Eine selbst geschriebene Klasse gehört fast sicher zur zweiten Art, denn ein Seitendesign von Grund auf lohnt sich selten. Die Konventionen von .cls und .sty sind nahezu gleich; die Befehle liegen nur paarweise als Class- und Package-Variante vor (\ProvidesClass\ProvidesPackage, \LoadClass\RequirePackage, \PassOptionsToClass\PassOptionsToPackage).

Die Standardoptionen, die deine Klasse akzeptieren sollte

Nutzer übergeben deiner Klasse Optionen genauso wie einer Standardklasse. Mindestens sollte daher die übliche Riege vorhanden sein: 10pt / 11pt / 12pt für die Grundschriftgröße, a4paper / letterpaper für das Papier, onecolumn / twocolumn für die Spalten, oneside / twoside für ein- oder zweiseitigen Satz und draft, das übervolle Zeilen mit einem schwarzen Balken markiert (Gegenstück final). Selbst implementieren musst du nichts davon: Wie gleich zu sehen, ist es üblich, sie an die Basisklasse weiterzureichen.

OptionBedeutungStandard
10pt / 11pt / 12ptGrundschriftgröße des Textkörpers10pt
a4paper / letterpaperPapierformat (auch b5paper, legalpaper, …)letterpaper
onecolumn / twocolumneinspaltig / zweispaltigonecolumn
oneside / twosideeinseitiges / zweiseitiges Layoutoneside (bei book jedoch twoside)
draft / finalob übervolle Zeilen einen schwarzen Balken erhaltenfinal

Soll die Klasse selbst festlegen, was ohne Angabe des Nutzers gilt, schreibt man \ExecuteOptions{a4paper,11pt} vor \ProcessOptions. Damit wird erklärt: „Führe den Code dieser Optionen vorab aus.“ Genau diese Form nennt der clsguide, um einer Klasse ihr Standarddesign zu geben. Das Verwenden dieser Optionen auf der \documentclass[...]-Seite des Dokuments sowie book-eigene Optionen wie openright gehören zur Seite über Dokumentklasse und Präambel. Ab hier konzentrieren wir uns darauf, die empfangende Klasse zu schreiben.

Die Datei am Anfang ausweisen: \NeedsTeXFormat und \ProvidesClass

Die ersten zwei Zeilen einer Klassendatei (myclass.cls) sind fast Boilerplate. \NeedsTeXFormat{LaTeX2e} erklärt, dass die Datei für LaTeX2e gedacht ist. Danach meldet \ProvidesClass{myclass}[2026/01/01 v1.0 My example class] Klassenname, Veröffentlichungsdatum, Version und Kurzbeschreibung. Wirklich nützlich wird diese Zeile im Log: Nach der Übersetzung steht dort Document Class: myclass 2026/01/01 v1.0 My example class. Meldet ein Mitautor, das Dokument lasse sich nicht bauen, verrät schon diese eine Zeile, ob dort eine alte .cls liegt.

Der Teil in eckigen Klammern ist optional, erlaubt aber, über das Datum im Format YYYY/MM/DD eine Mindestversion zu verlangen, etwa \documentclass{myclass}[2026/01/01]. Beim Schreiben eines Pakets lautet das Gegenstück \ProvidesPackage{mypackage}[2026/01/01 v1.0 ...]; \NeedsTeXFormat ist bei beiden gleich. Feste Regel: Der Name in \ProvidesClass muss dem tatsächlichen Dateinamen entsprechen – in myclass.cls steht also immer \ProvidesClass{myclass}.

latex
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2026/01/01 v1.0 My example class]

Optionen deklarieren: \DeclareOption und \CurrentOption

Jede Option, die deine Klasse akzeptiert, wird mit \DeclareOption{option}{code} einzeln deklariert. Gibt der Nutzer sie an, läuft ihr code in dem Moment, in dem \ProcessOptions erreicht wird (siehe unten). Der Code darf jede gültige LaTeX-Konstruktion sein, ist in der Praxis aber meist eine einzige Zeile, die ein mit \newif erzeugtes Boolesches Flag setzt; die eigentliche Arbeit später anhand des Flags zu erledigen, verhindert Reihenfolgeprobleme.

Die Auffangstelle für nicht deklarierte Optionen ist das gesternte \DeclareOption*{code}; darin expandiert \CurrentOption zum Namen der gerade verarbeiteten Option. Die häufigste Zeile einer eigenen Klasse nutzt sie, um unbekannte Optionen unverändert an die Basisklasse weiterzureichen. Dank dieser Zeile können Nutzer 10pt oder a4paper selbstverständlich übergeben, obwohl du sie nie deklariert hast – du hast damit die eingangs beschriebene Voreinstellung „eine Klasse reicht stillschweigend weiter“ auf ein von dir gewähltes Ziel umgelenkt.

latex
% pass anything we do not handle ourselves on to article
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}

Optionen verarbeiten, dann die Basisklasse laden: \ProcessOptions und \LoadClass

Deklarieren allein bewirkt nichts; der Code der gewählten Optionen läuft erst beim Aufruf von \ProcessOptions. In der Praxis schreibt man fast immer \ProcessOptions\relax. Da es auch ein gesterntes \ProcessOptions* gibt, wählt das abschließende \relax zuverlässig die ungesternte Form und verhindert unnötiges Vorauslesen sowie möglicherweise irreführende Fehlermeldungen – der clsguide empfiehlt das ausdrücklich. Die ungesternte Form verarbeitet Optionen in der Reihenfolge ihrer Deklaration, die gesternte in der Reihenfolge, in der der Aufrufer sie aufgeführt hat.

Ein Seitendesign von Grund auf zu bauen lohnt sich selten, daher stehen die meisten eigenen Klassen auf einer vorhandenen. Das leistet \LoadClass[options]{article}: Es lädt sämtliche Befehle und das Styling von article.cls. Der Befehl darf nur in einer Klassendatei und höchstens einmal pro Klassendatei verwendet werden. Die Reihenfolge zählt: Damit die vom Nutzer bei \documentclass[...] gegebenen Optionen die Basisklasse erreichen, steht \LoadClass nach der Optionsverarbeitung (\ProcessOptions) – erst die Weiterleitung deklarieren, dann \ProcessOptions verteilen lassen, dann die Basis laden. Sollen genau die empfangenen Optionen weitergereicht werden, ist \LoadClassWithOptions{article} die Abkürzung; in einem Paket tritt \RequirePackage an die Stelle von \LoadClass, und für den Alles-durchreichen-Fall \RequirePackageWithOptions.

Alles nach \LoadClass ist der Ort, an dem endlich der Charakter deiner Klasse entsteht: Überschriften mit \renewcommand umdefinieren, Ränder mit \setlength anpassen, neue Befehle und Umgebungen mit \newcommand / \newenvironment definieren. Zusätzliche Pakete werden ab hier mit \RequirePackage geladen. Umgekehrt gemerkt: Vor \LoadClass gehören nur Deklaration und Verarbeitung der Optionen – dann stellen sich Reihenfolgefragen gar nicht mehr.

Vollständiges Beispiel: eine minimale Klasse, die article erweitert

Zusammengesetzt ergibt das folgende minimale .cls. Sie baut auf article auf, ergänzt eine eigene draft-Option, leitet unbekannte Optionen an article weiter, gibt a4paper als Voreinstellung vor und richtet zuletzt Ränder und Abschnittsnummerierung nach eigenem Geschmack ein. Speichere sie als myclass.cls neben dem Manuskript und verwende sie im Dokument mit \documentclass[11pt,a4paper,draft]{myclass}.

latex
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2026/01/01 v1.0 My example class]

% --- declare options ---
\newif\if@my@draft \@my@draftfalse
\DeclareOption{draft}{\@my@drafttrue}
% forward everything else to article
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}

% --- defaults, then execute, then load the base class ---
\ExecuteOptions{a4paper}
\ProcessOptions\relax
\LoadClass{article}

% --- this class's own character ---
\RequirePackage[margin=25mm]{geometry}
\setlength{\parindent}{0pt}
\renewcommand{\thesection}{\Alph{section}}
\if@my@draft
  \AtBeginDocument{\typeout{myclass: DRAFT MODE}}
\fi

\endinput

Das abschließende \endinput sagt LaTeX, dass die Datei hier endet; es gehört zur Konvention, und Notizen oder Beispiele dahinter werden nie gelesen. Für ein Paket tauscht man \ProvidesClass gegen \ProvidesPackage und \LoadClass gegen \RequirePackage: Dasselbe Gerüst wird zur .sty.

Der moderne Weg: \DeclareKeys und \ProcessKeyOptions

\DeclareOption ist weiterhin völlig gültig, ist aber auf Vorhanden/Nicht-vorhanden-Schalter zugeschnitten; eine Option mit Wert wie logo=acme.pdf müsste man selbst zerlegen. Deshalb bringt der LaTeX-Kernel inzwischen eine eigene Schlüssel-Wert-Schnittstelle mit: Schlüssel mit \DeclareKeys deklarieren und mit \ProcessKeyOptions verarbeiten. Jeder Schlüsselname trägt eine „Property“, die sein Verhalten bestimmt; die grundlegenden sind .code (beliebigen Code ausführen), .if / .ifnot (einen TeX-Booleschen Schalter setzen), .store (den Wert in einem Makro sichern) und .usage (ob die Option nur beim Laden, überall in der Präambel oder ohne Einschränkung angegeben werden darf). Unbekannte Schlüssel übernimmt \DeclareUnknownKeyHandler, und nach \ProcessKeyOptions muss \ProcessOptions nicht zusätzlich aufgerufen werden.

latex
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{keyclass}[2026/01/01 v1.0 Key-value demo class]

\DeclareKeys[keyclass]{
  draft.if   = @keyclass@draft,
  logo.store = \@keyclass@logo,
  logo.usage = load
}
% anything that is not one of our keys goes to article
\DeclareUnknownKeyHandler[keyclass]{%
  \PassOptionsToClass{\CurrentOption}{article}}
\ProcessKeyOptions[keyclass]   % no \ProcessOptions needed
\LoadClass{article}

\endinput

Dieser Mechanismus stammt ursprünglich vom Paket l3keys2e, dessen Kern inzwischen in den LaTeX2ε-Kernel gewandert ist (der mit TeX Live 2024 ausgelieferte Kernel ist LaTeX2e 2023-11-01 und stellt \DeclareKeys, \ProcessKeyOptions und \SetKeys bereit). In vorhandenen Paketen wird l3keys2e stellenweise weiterhin geladen; jlreq.cls etwa führt nahe am Anfang \RequirePackage{l3keys2e} aus. Die Wahl ist einfach: Nimmt auch nur eine Option einen Wert entgegen, verwende \DeclareKeys; sind es lauter Ein/Aus-Schalter, genügt \DeclareOption. Für Einstellungen nach dem Laden dient \SetKeys.

Der Minimaltest vor der Weitergabe

Eine Klasse wirkt sich in dem Moment auf das gesamte Dokument aus, in dem sie geladen wird. Kläre ihr Verhalten daher mit einem winzigen Testdokument, bevor echter Inhalt entsteht. Zu prüfen sind nur zwei Dinge: dass Standardoptionen wie 11pt oder twocolumn die Basisklasse erreichen und dass ausschließlich die eigenen Optionen vom eigenen Code behandelt werden. Verhält es sich hier nicht wie erwartet, liegt es fast sicher an der Position von \ProcessOptions, der Weiterleitung in \DeclareOption* oder der Reihenfolge von \LoadClass.

latex
\listfiles                     % log every file and version that is loaded
\documentclass[11pt,a4paper,draft]{myclass}
\begin{document}
\section{Smoke test}
Check the body size, the paper, the draft switch,
the heading style and the margins.
\end{document}
  • Weist das Log die Klasse aus? Prüfe, dass die Zeile Document Class: myclass ... mit dem Datum und der Version aus \ProvidesClass im .log steht. Abweichende Datei- und Klassennamen verwirren später garantiert jemanden.
  • Sind die Standardoptionen erhalten? Wird 11pt oder twocolumn ignoriert, prüfe die Weiterleitung in \DeclareOption* oder die Position von \LoadClass.
  • Verschreibe eine Option absichtlich. Übersetze \documentclass[nosuchoption]{myclass} und sieh nach, ob Unused global option(s) im Log erscheint. Wenn nicht, schluckt sie ein Paket, an das du weiterleitest, stillschweigend.
  • Halte alles nach \endinput leer. Am Ende hinterlassene Notizen oder Beispiele werden gelesen, sobald diese Markierung verschwindet.

Auch an die Verteilungsform denken

Der eigentliche Test einer eigenen Klasse ist nicht der erste Erfolg auf dem eigenen Rechner, sondern der Moment, in dem jemand anders sie in einer anderen Umgebung lädt. Halte mindestens .cls, ein kurzes Beispieldokument, eine README und ein Changelog in einem Verzeichnis zusammen und prüfe, dass das Beispiel unverändert übersetzt. Trenne in der README die Optionen, die du an die Basisklasse weiterleitest, von denen, die deine Klasse selbst behandelt; so lässt sich nachvollziehen, wo 11pt wirkt. Wird das Ganze größer, wechsle zu LaTeXs eigenem doc und docstrip: Quelle und Erläuterung liegen gemeinsam in einer .dtx, aus einer .ins entsteht die .cls – damit laufen Verteilung und Dokumentation auf einer Spur.

terminal
myclass/
  myclass.cls
  sample.tex
  README.md
  CHANGELOG.md

Setze schließlich \listfiles ins Beispiel. Am Ende des Logs stehen dann alle geladenen Dateien samt Version, sodass sich auf einen Blick unterscheiden lässt, ob jemand eine alte lokale myclass.cls mit sich herumträgt oder ob die erwarteten Pakete tatsächlich geladen werden. Eine Klasse ist das Fundament des gesamten Dokuments: Auf lange Sicht zahlen sich saubere Ladereihenfolge, Optionsverarbeitung und Log-Informationen weit verlässlicher aus als ein weiteres Textkörper-Makro.