Im Editor sieht das Template richtig aus, dann kommt das PDF zurück, und der Text ist etwas breiter, etwas runder, und die Zeile, die eben noch passte, bricht um. Fehlgeschlagen ist nichts. Kein Fehler, keine Warnung, keine Logzeile. Das PDF enthält einfach eine andere Schrift als die, die das Template verlangt.
Das kann bei jedem HTML-zu-PDF-Dienst passieren, der Chromium auf einem Linux-Server betreibt, bei uns auch. Wir haben vier einzeilige Templates mit unserem Render-Worker gerendert (Chromium 153, das Image, das wir in Produktion betreiben) und ausgelesen, welche Schriften jedes PDF eingebettet hat.

| Das Template sagt | Das PDF enthält |
|---|---|
font-family: "Segoe UI", Helvetica, sans-serif |
Liberation Sans |
font-family: Inter, sans-serif, nichts geladen |
Liberation Sans |
font-family: Inter, sans-serif, <link> zu Google Fonts |
Inter |
dasselbe, Text mit ✓, ✗ und → |
Inter, DejaVu Sans für ✓ und ✗, Liberation Sans für → |
Ein Schriftname ist ein Wunsch
font-family ist eine Liste von Namen, und der Browser nimmt den ersten, den er hat. Auf einem
Windows-Laptop ist das Segoe UI. Ein Linux-Server hat weder Segoe UI noch Helvetica, also geht
Chromium die Liste hinunter, landet bei sans-serif, und das System gibt ihm Liberation Sans. Das
ist keine schlechte Schrift: Sie wurde mit den Breiten von Arial gebaut, eine für Arial gesetzte
Zeile behält also ihre Länge. Es ist nur nicht die Schrift, die im Template steht.
Die zweite Zeile ist die, bei der man hängen bleibt. Inter sieht aus wie eine Schrift, die das
Template hat. Auf dem Rechner der Designerin ist sie installiert, die Vorschau im Editor zeigt Inter,
alle sind zufrieden. Der Server hat sie nicht, und nichts im Template sagt Chromium, woher er sie
bekommt. Das PDF kommt in Liberation Sans, und die ersten beiden Zeilen im Bild sind dieselbe Zeile.
Die Abhilfe: Jede Schrift laden, die man nennt. Entweder ein <link> zu Google Fonts oder einem
anderen Webfont-Dienst im Head des Templates, oder eine @font-face-Regel mit der Datei. Für eigene
Schriften — eine lizenzierte Hausschrift — nimmt Formfeed die Dateien einmal pro Organisation unter
Schriften entgegen und fügt die @font-face-Regel in jedes Rendering ein, das die Familie nennt,
auch in Kopf- und Fußzeilen, deren eigenes Dokument das Stylesheet des Templates nie sieht (ab
Starter).
Das PDF prüfen, nicht die Vorschau
Die Vorschau im Browser verwendet die Schriften Ihres Rechners, sie kann also nicht zeigen, was dem Server fehlt. Das PDF kann es. Es führt jede eingebettete Schrift auf:
pdffonts rechnung.pdfaus den poppler-utils gibt eine Zeile pro Schrift aus.- In Acrobat oder Acrobat Reader: Datei → Eigenschaften → Schriften.
- Der PDF-Viewer von Chrome hat keine solche Liste; öffnen Sie die Datei in einem der obigen.
Die Namen haben ein Präfix aus sechs Buchstaben wie ABCDEF+Inter-Regular. Das heißt, das PDF
enthält eine Teilmenge: nur die Zeichen, die das Dokument verwendet, damit es klein bleibt. Steht in
der Liste LiberationSans, DejaVuSans oder NotoSans, obwohl Ihr Template etwas anderes nennt,
wurde entweder eine Schrift nie geladen, oder einige Zeichen fehlten in ihr (dazu unten mehr).
Was eine Google-Schrift kostet
Der Worker muss eine Webschrift holen, bevor er drucken kann, und er wartet auf
document.fonts.ready; eine Schrift, die noch nicht da ist, wird also nie übergangen. Das Holen
kostet Zeit. Wir haben dreimal einen frischen Worker mit leerem Cache gestartet, eine schlichte Seite
einmal zum Aufwärmen gedruckt und dreimal zum Messen, dann das Inter-Template einmal und danach noch
dreimal. Der Worker meldet seine Renderzeit selbst.
| Renderzeit (Median) | |
|---|---|
| Seite ohne Webschriften | 58 ms |
| Inter, erstes Rendering, leerer Cache | 318 ms |
| Inter, jedes Rendering danach | 72 ms |
Das erste Rendering hat Googles Stylesheet und die Schriftdateien geholt; die folgenden fanden beides im Disk-Cache des Workers und kosteten 14 ms mehr als eine Seite ganz ohne Webschrift. In Produktion liegt dieser Cache auf einem Datenträger, der Neustarts und Deployments überdauert und eine Datei eine Woche behält, geholt wird also einmal pro Server und Woche, nicht einmal pro Dokument. Organisationsschriften kommen aus unserem eigenen Speicher und laufen durch denselben Cache.
Das sind die Zahlen eines Laptops in Deutschland, der mit Google spricht, ohne dass daneben etwas Schweres lief; neben drei laufenden Builds dauerten dieselben Läufe vier- bis fünfmal so lange, im selben Verhältnis. Es geht um das Muster, nicht um die Millisekunden. Ein Dienst ohne solchen Cache zahlt die erste Zeile bei jedem Rendering.
Ein Häkchen aus einer dritten Schrift
Die letzte Zeile ist die unauffälligste. Inter wurde geladen, die Wörter sind Inter, und trotzdem
bettet das PDF drei Schriften ein. Die Inter-Dateien, die Google für diese Anfrage geliefert hat,
enthalten kein ✓ und kein ✗, also hat Chromium jedes dieser Zeichen in den auf dem Server
installierten Schriften gesucht und in DejaVu Sans gefunden; der Pfeil kam aus Liberation Sans.
Sehen Sie aufs Bild: Das Häkchen ist kräftiger als die Buchstaben daneben, der Pfeil sitzt tiefer.
Chromium entscheidet das Zeichen für Zeichen, stillschweigend, und das Ergebnis hängt davon ab, was auf dem Server installiert ist — unser Image bringt DejaVu, Liberation und die Noto-Familien mit, leere Kästchen gibt es also nicht, aber durchaus ein anderes Design. Drei Auswege:
- Eine Schrift wählen, die die verwendeten Symbole hat, und sie laden.
- Eine zweite Schrift nur für die Symbole laden (etwa Noto Sans Symbols 2) und sie nach der
Textschrift nennen:
font-family: Inter, "Noto Sans Symbols 2", sans-serif. - Statuszeichen als Inline-SVG zeichnen, über das keine Schrift entscheidet.
Kurz gesagt
- Nur Schriften nennen, die man lädt, und jede Schrift laden, die man nennt.
- Die Schriftenliste des PDFs lesen, nicht das Aussehen der Vorschau.
- Das erste Rendering mit einer Webschrift ist langsamer; danach sollte ein Cache es kostenlos machen.
- Symbole fallen Zeichen für Zeichen zurück. Wenn es auf sie ankommt, eine Schrift mitbringen, die sie hat.
Die vier PDFs zum Selbstprüfen: Segoe UI, Inter nicht geladen, Inter von Google Fonts, mit Symbolen. Die Dokumentation beschreibt Schriften in Templates und das Brand Kit, dessen Überschrift- und Textschrift jedes Template als CSS-Variablen erreicht.

