Was HTML zu PDF tatsächlich übersteht, gemessen
Zwölf Print-CSS-Funktionen, gerendert durch headless Chromium und dann aus dem PDF ausgelesen — Seitenumbrüche, @page-Größen, wiederholte Tabellenköpfe, Links und Schriftarten. Zwei davon funktionieren nicht, und eine häufige Falle liegt an der API, nicht am CSS.
Was ist hier neu: Eine Unterstützungsmatrix pro Funktion für HTML-zu-PDF-Druck-CSS, gemessen auf Chromium 148 durch Rendern jedes Falls und Inspizieren der Seitenzahl, Seitendimensionen, Link-Annotationen und Text pro Seite des resultierenden PDFs — nicht durch Lesen der Dokumentation. Jedes Urteil ist anhand des veröffentlichten Testrahmens und des Datensatzes reproduzierbar, und zwei weit empfohlene Techniken werden als nicht funktionierend gezeigt.
Jeder HTML-zu-PDF-Dienst behauptet, dass seine Ausgabe treu ist. Keiner von ihnen veröffentlicht, was das bedeutet. Also haben wir es gemessen: zwölf Print-CSS-Funktionen, jede durch Chromium im Headless-Modus gerendert – die Engine hinter MostlyRender und hinter den meisten HTML-zu-PDF-Diensten – und dann aus dem resultierenden PDF wieder ausgelesen.
Nichts hier ist aus der Dokumentation zitiert. Jedes Ergebnis kommt aus der Überprüfung der Datei: wie viele Seiten sie hat, welche Größe sie haben, welcher Text auf welcher Seite landete, ob eine Link-Annotation existiert, ob eine Schriftart eingebettet wurde.
# Die Matrix
Gemessen auf Chromium 148.0.7778.96, zuerst am 1. September 2026 und wieder am 27. September 2026. Beide Läufe führten zu denselben zwölf Ergebnissen.
| Feature | Funktioniert | Was wir beobachteten |
|---|---|---|
break-after: page |
Ja | 2 Seiten, wie verlangt |
page-break-after: always (veraltet) |
Ja | 2 Seiten – die alte Schreibweise wird immer noch berücksichtigt |
break-inside: avoid |
Ja | Der Block wurde ganz auf Seite 2 verschoben, anstatt geteilt zu werden |
@page { size: A5 } |
Ja | 420×595pt – genau A5 |
@page { size: A4 landscape } |
Ja | 842×595pt – Querformat |
Wiederholendes <thead> über Seiten hinweg |
Ja | 3 Seiten, Header auf Seite 2 vorhanden |
position: fixed als laufende Kopfzeile |
Ja | Vorhanden auf 2 von 2 Seiten |
@page Marginalienbereiche + counter(page) |
Nein | Keine Seitennummer irgendwo in der Ausgabe |
<a href> als anklickbarer Link |
Ja | Link-Annotation vorhanden |
Interne #anchor Links |
Ja | Ziel vorhanden |
| Schriftarten-Einbettung | Ja | DejaVuSansMono eingebettet und Teilmenge |
| CSS Grid über einen Seitenumbruch hinweg | Nein | Alle 8 Zellen auf Seite 1; Seite 2 leer |
Zehn von zwölf funktionieren. Die beiden, die nicht funktionieren, sind wichtig zu kennen, bevor Sie Ihr Design um sie herum planen.
# Die beiden, die fehlschlagen
CSS Paged Media Marginalienbereiche werden nicht gerendert. Die Spezifikation gibt dir @page { @bottom-center { content: "Page " counter(page) } }, es ist in jedem Tutorial zum Drucken aus dem Web zu finden, und Chromium ignoriert es. Wir fanden überhaupt keine Seitennummer in der Ausgabe.
Wenn du Seitennummern benötigst, müssen sie von dem Tool hinzugefügt werden, das die PDF erzeugt – deshalb bieten Tools, die Seitennummerierung anbieten, dies als eine Funktion an, anstatt dir zu sagen, CSS zu schreiben.
CSS Grid wird nicht fragmentiert. Wir layouteten acht Elemente in einem zweispaltigen Grid, das hoch genug war, um zwei Seiten zu benötigen. Alle acht wurden auf Seite eins gerendert, und Seite zwei kam leer heraus. Grid funktioniert hervorragend für Inhalte, die auf eine einzelne Seite passen; für alles, das paginiert, verwenden Sie Block-Fluss oder eine Tabelle.
# Das Fallstricke, das überhaupt nicht CSS ist
Beim Erstellen des Testrahmens notierten wir @page { size: A5 } als nicht unterstützt – und es war unser eigener Fehler. Dem Renderer wurde durch den API-Aufruf mitgeteilt, A4 zu verwenden, und ein vom Aufrufer übergebenes Papierformat überschreibt die @page-Größe des Dokuments stillschweigend. Wenn das Format weggelassen wird und CSS-Seitengröße bevorzugt wird, wurden A5 und das Querformat genau richtig gerendert.
Dies ist es wert, deutlich auszusprechen, da es fast sicherlich der häufigste Grund ist, warum Menschen zu dem Ergebnis kommen, dass @page nicht funktioniert: Das CSS ist in Ordnung, und etwas weiter oben in der Kette überschreibt es stillschweigend. Wir merkten es nur, weil ein Ergebnis, das der Spezifikation widersprach, uns dazu veranlasste, unseren Testrahmen erneut zu überprüfen, statt einfach das Ergebnis zu veröffentlichen.
# Dies reproduzieren
Der Testrahmen und der Datensatz hinter der Tabelle sind beide veröffentlicht:
- bench-htmltopdf.js startet Chromium, rendert jeden Fall und inspiziert die Ausgabe mit pdf-lib und pdf.js.
- html-to-pdf.json ist die Ausgabedatei, die dieser Tabelle zugrunde liegt, mit der Chromium-Version gekennzeichnet, die sie gemessen hat.
Um es selbst auszuführen, speichern Sie den Testrahmen in einem leeren Ordner und führen Sie aus:
npm i playwright pdf-lib pdfjs-dist@3
npx playwright install chromium
node bench-htmltopdf.js
Eine erwähnenswerte Einschränkung: Die Schriftartenerkennung scannt die rohen PDF-Bytes nach Schriftnamen, sodass ein positives Ergebnis zuverlässig ist, aber ein leeres nur bedeutet „nicht sichtbar für diese Methode". Der Testrahmen stuft diesen Fall als uneindeutig ein und nicht als Fehler, da die Aussage „Schriftarten sind nicht eingebettet" – gestützt auf eine Methode, die sie möglicherweise nicht sieht – genau die Art von unbewiesener Aussage ist, die dieser Artikel vermeiden soll.
# Warum wir es gemessen haben
Wir bauen ein HTML-zu-PDF-Tool und eine API auf dieser Engine. Die Dokumentation dessen, was es kann und nicht kann, ist nützlicher als die bloße Behauptung, dass es zuverlässig ist – und falls eine Zahl hier fehlerhaft ist, ist der Testrahmen, der sie erzeugt hat, oben verlinkt und kann von Ihnen ausgeführt werden.
Häufig gestellte Fragen
Funktioniert page-break-after noch, oder brauche ich break-after?
Beides funktioniert. Wir haben das moderne break-after: page und das ältere page-break-after: always separat gemessen und beide erzeugten das erwartete zweiseitige Dokument auf Chromium 148. Falls Sie ältere Vorlagen verwenden, die die ältere Schreibweise verwenden, sind sie nicht der Grund, warum Ihre Paginierung falsch ist.
Warum wird meine @page-Größe ignoriert?
Fast immer, weil der Aufrufer es überschrieben hat. Falls die API oder Bibliothek, die das Rendern durchführt, ein eigenes Papierformat übergibt, setzt dieses sich durch und Ihr @page { size: … } wird stillschweigend verworfen. Mit ausgelassenem Format und bevorzugter CSS-Seitengröße kamen A5 und Querformat genau wie gewünscht raus. Dies ist die häufigste falsche Aussage von "@page size funktioniert nicht" — es hat uns beim Erstellen des Test-Systems für diesen Artikel erwischt.
Kann ich Seitenzahlen mit CSS in den Rand einfügen?
Nicht in Chromium. @page { @bottom-center { content: counter(page) } } ist Teil von CSS Paged Media und ist weitgehend dokumentiert, aber das Randfeld wird einfach nicht gerendert — wir haben es gemessen und nirgends eine Seitenzahl in der Ausgabe gefunden. Seitenzahlen müssen vom Konvertierungs-Tool kommen, nicht von Ihrem Stylesheet.
Werden CSS-Grid-Layouts richtig über Seiten verteilt?
Nein. In unserem Test wurden alle acht Grid-Elemente auf der ersten Seite gerendert und die zweite Seite war leer — das Grid wurde nicht fragmentiert. Wenn Ihr Dokument lang genug ist, um sich über mehrere Seiten zu erstrecken, legen Sie den wiederholenden Teil mit normalem Block-Fluss oder einer Tabelle aus und verwenden Sie Grid nur für Inhalte, die auf eine Seite passen.
Bleiben Hyperlinks im PDF erhalten?
Ja. Sowohl ein externes <a href> als auch ein interner #anchor erzeugten echte Link-Annotationen in der Ausgabedatei, sodass Links anklickbar bleiben und ein generiertes Inhaltsverzeichnis navigierbar bleibt.