Zum Hauptinhalt springen
Rezept Nummer 176

Rezepte · Kapitel 2 · Schrift und Text

Mediäval-, Versal- und Tabellenziffern

Thoreaus Rechnungen aus Walden: figureStyle setzt Versalziffern in Kapitälchen-Überschriften und Tabellenziffern in die Rechnungen; der Text bleibt mediäval.

Auf dieser Seite
Ausgabe
Canvas · PDF
Stufe
Mittel
Postext
Getestet mit Postext 1.65.0
Erfordert ≥ 1.65.0 · postext-pdf ≥ 1.65.0
Lizenz
Aktualisiert am 31. Okt. 2026
Code MIT · Text CC BY 4.0

S. 1 von 6

  • Englisches Beispiel: noch keine deutsche Ausgabe
  • Endformat 140 × 216 mm
  • 1 Spalte
  • Alegreya 10,8/14,5
  • Alegreya SC
  • Alegreya SC@lnum
  • Alegreya Sans
  • Alegreya@tnum
  • 6 Seiten
  • Stufe
  • Postext 1.65.0
  • In 124 ms gesetzt
  • 160 Zeilen Code

Kurz gesagt

Eine kleine Ausgabe der Haushaltsrechnungen, die Thoreau in Walden abdruckte. Die Zahlen im Text sind klein wie Kleinbuchstaben, die Jahreszahlen der Überschriften so hoch wie Großbuchstaben, die Beträge stehen in Spalten.

Was Sie setzen

Eine kleine Ausgabe der Rechnungen, die Thoreau im ersten Kapitel von Walden abdruckte: was sein Haus kostete, was das Bohnenfeld einbrachte, was er in acht Monaten aß. Sie steht auf einer Seite von 140 × 216 mm in der Alegreya-Familie, mit dem Stich der Hütte von 1854 über der Eröffnung. Die Ziffern wechseln mit ihrer Aufgabe. Im Text stehen March, 1845 und $13.34 in Mediävalziffern, die wie Kleinbuchstaben auf- und absteigen, sodass die Daten nicht aus der Zeile fallen. Die Überschriften sind Kapitälchen, und ihre Jahreszahlen sind so hoch wie die Großbuchstaben. In den Rechnungen ist jede Ziffer gleich breit, und die Cent von dreizehn Zeilen Bretter, Latten und Nägel stehen bis zur Summe untereinander.

Dieses Rezept beantwortet

  • Wie setze ich Mediävalziffern im Fließtext, Versalziffern in den Überschriften und Tabellenziffern in den Tabellen?
  • Wie setze ich nicht nummerierte Grafiken: Ornamente, Vignetten, Logos?

Die kurze Antwort

script.js · Zeilen 34–55im vollständigen Code
// Alegreya's own figures are old-style, so the prose asks for none: the cut Fontsource
// serves has no onum, and 'oldstyle' would change nothing (see the write-up).
const bodyText = {
  fontFamily: TEXT, fontSize: pt(10.8), lineHeight: pt(LEAD), color: col('ink'),
  boldColor: col('ink'), italicColor: col('ink'), referenceColor: col('ink'),
  textAlign: 'justify', firstLineIndent: mm(4.5), indentAfterHeading: false,
  hyphenation: { enabled: true }, optimalLineBreaking: true,
  avoidWidows: true, avoidOrphans: true, avoidRunts: true,
};
// Small capitals take lining figures (lnum), at the height of the capitals around them.
const section = { level: 2, fontFamily: CAPS, fontSize: pt(12.5), lineHeight: pt(LEAD),
  fontWeight: 400, letterSpacing: pt(0.6), color: col('accent'), figureStyle: 'lining',
  marginTop: pt(LEAD), marginBottom: pt(0) };
// The accounts: every figure on one width (tnum), so the cents stand in columns.
// 'tabular' keeps the font's form, old-style; 'lining-tabular' would set them at cap height.
const tableStyle = {
  figureStyle: 'tabular', bodyFontFamily: TEXT, bodyFontSize: pt(9.8), bodyColor: col('ink'),
  rules: 'booktabs', groupRules: true, borderColor: col('rule'), lightRuleWidth: pt(0.4),
  heavyRuleWidth: pt(0.7), headerBackgroundEnabled: false, headerFontFamily: TEXT,
  headerFontSize: pt(9.8), headerColor: col('ink'), headerBold: false, headerItalic: false,
  cellPadding: mm(0.7),
};

Zutaten

Schrift
Alegreya, Alegreya SC, Alegreya Sans (SIL OFL 1.1)
Dateien
  • cabin-860.jpg
  • The vignette of Thoreau’s cabin from the title page of the first edition (1854), cropped and levelled to black on white (Ticknor and Fields, Boston, 1854 (engraver unknown), gemeinfrei)

Zubereitung

#1 · Eine Ziffernart je Textstil

Der Code dieses Schritts ist die kurze Antwort weiter oben. figureStyle verlangt von der Schrift eines Stils ihre OpenType-Ziffern (Ziffernarten). Der Grundtext verlangt nichts, denn Alegreyas eigene Ziffern sind schon Mediävalziffern mit eigener Breite: die 1 ist 342 Einheiten breit, die 0 533. Die Überschriften der zweiten Ebene verlangen von Alegreya SC 'lining', ihre lnum-Ziffern, die so hoch sind wie die Großbuchstaben daneben. Der Tabellenstil verlangt 'tabular', das tnum der Schrift: Die Ziffern behalten ihre Mediävalform und werden alle gleich breit, 450 Einheiten, sodass sich eine Spalte von Preisen von oben nach unten liest. Mit 'lining-tabular' stünden sie auf Versalhöhe (siehe „Varianten“).

#2 · Die Rechnungen sind Tabellen mit fünf Spalten

script.js · Zeilen 59–122im vollständigen Code
// A row starting '=' is a total (header cells: a light rule above it), '+' heads a group.
const C = (content, align = 'left', extra = {}) => ({ content, align, ...extra });
function account(tsv) {
  const rows = tsv.replace(/^\n+|\n+$/g, '').split('\n').map((line) => {
    const total = line.startsWith('='), group = line.startsWith('+');
    const [item, dollar, amount, fraction, remark] = line.replace(/^[=+]/, '').split('\t');
    if (group) return [C(item, 'left', { colSpan: 5, isHeader: true }),
      ...[1, 2, 3, 4].map(() => C('', 'left', { hiddenBy: { row: -1, col: 0 } }))];
    const h = { isHeader: total };
    return [C(item, 'left', h), C(dollar ? '\\$' : '', 'right', h), // `$` alone opens maths
      C(amount ?? '', 'right', h), C(fraction ?? '', 'left', h), C(remark ?? '', 'left', h)];
  });
  rows.forEach((row, r) => row.forEach((cell) => cell.hiddenBy && (cell.hiddenBy.row = r)));
  return { rows, headerRowCount: 0, columnWidths: [34, 2.4, 8, 3.6, 35] };
}
const accounts = String.raw`=== house
Boards,	$	8.03	½	mostly shanty boards.
Refuse shingles for roof sides,		4.00
Laths,		1.25
Two second-hand windows with glass,		2.43
One thousand old brick,		4.00
Two casks of lime,		2.40		That was high.
Hair,		0.31		More than I needed.
Mantle-tree iron,		0.15
Nails,		3.90
Hinges and screws,		0.14
Latch,		0.10
Chalk,		0.01
Transportation,		1.40		I carried a good part on my back.
=In all,	$	28.12	½
=== farm
	$	23.44
Deducting the outgoes,		14.72	½
=There are left,	$	8.71	½
=== food
Rice,	$	1.73	½
Molasses,		1.73		Cheapest form of the saccharine.
Rye meal,		1.04	¾
Indian meal,		0.99	¾	Cheaper than rye.
Pork,		0.22
+All experiments which failed:
Flour,		0.88		Costs more than Indian meal, both money and trouble.
Sugar,		0.80
Lard,		0.65
Apples,		0.25
Dried apple,		0.22
Sweet potatoes,		0.10
One pumpkin,		0.06
One watermelon,		0.02
Salt,		0.03
=== outgoes
House,	$	28.12	½
Farm one year,		14.72	½
Food eight months,		8.74
Clothing, etc., eight months,		8.40	¾
Oil, &c., eight months,		2.00
=In all,	$	61.99	¾
=== income
	$	23.44
Earned by day-labor,		13.34
=In all,	$	36.78
`; // content.accounts.<lang>.md: one block per table
const tables = Object.fromEntries(accounts.split(/^=== /m).filter(Boolean)
  .map((block) => [block.slice(0, block.indexOf('\n')).trim(), block.slice(block.indexOf('\n'))]));

Thoreaus Rechnungen liegen als TSV in content.accounts.en.md, ein Block je Rechnung, und die spanische Ausgabe übersetzt die Posten und setzt das Dezimalkomma, ohne den Code anzufassen. Jede Zeile hat einen Posten, das Dollarzeichen, den Betrag, einen Bruch und eine Bemerkung. Halbe und Viertel haben eine eigene Spalte: ½ ist 713 Einheiten breit und ¾ 689, mehr als eine Tabellenziffer, und Alegreya hat kein Ziffernleerzeichen, um die anderen Beträge aufzufüllen. Eine Summe besteht aus Kopfzellen, darum zieht groupRules eine feine Linie darüber, wie Thoreaus Drucker vor In all einen Strich zog. Das Dollarzeichen wird \$ geschrieben, denn ein einzelnes $ öffnet in einer Zelle wie im Text eine Formel. Der Ressourcentyp account hat weder Nummer noch Beschriftungspräfix, und seine Standardplatzierung ist 'here': Jede Rechnung steht dort, wo Thoreaus Satz sie ankündigt.

#3 · Die Eröffnung nennt ihre Ziffern selbst

script.js · Zeilen 126–144im vollständigen Code
const at = (to, edge, y, x = 0) => ({ anchor: { to, edge }, offset: { x: mm(x), y: mm(y) } });
// 'below' starts a text at the left edge of what it hangs from: the texts take the measure
// and start half the difference to the left of the vignette, so they centre on the page.
const centred = (to, y) => ({ ...at(to, 'below', y, (VIGNETTE - MEASURE) / 2),
  size: { width: mm(MEASURE) } });
const opener = { enabled: true, minHeight: pt(19 * LEAD), slot: { elements: [
  { kind: 'image', id: 'cabin', resourceId: 'cabin',
    placement: { ...at('container', 'top', 0), size: { width: mm(VIGNETTE) } } },
  { kind: 'text', id: 'kicker', content: '{attr.kicker}', fontFamily: LABEL, fontWeight: 500,
    fontSize: pt(7.5), letterSpacing: pt(1.5), textTransform: 'uppercase', color: col('accent'),
    align: 'center', placement: centred('#cabin', 6) },
  { kind: 'text', id: 'title', content: '{titleText}', fontFamily: CAPS, fontSize: pt(30),
    letterSpacing: pt(1.2), lineHeight: 1, color: col('ink'), align: 'center',
    placement: { ...at('#kicker', 'below', 2.5), size: { width: mm(MEASURE) } } },
  // A design text names its own family, so it states its figures too.
  { kind: 'text', id: 'dates', content: '{attr.dates}', fontFamily: CAPS, fontSize: pt(11),
    letterSpacing: pt(0.8), color: col('accent'), align: 'center', figureStyle: 'lining',
    placement: { ...at('#title', 'below', 2.5), size: { width: mm(MEASURE) } } },
] } };

Ein Gestaltungstext legt seine eigene Familie fest, also erreichen ihn die Ziffern des Grundtexts nicht. Concord, 1845–1847 steht in Alegreya SC und verlangt selbst 'lining', wie die Überschriften. Die Vignette ist der Stich vom Titelblatt von 1854, beschnitten und auf Schwarz auf Weiß gebracht; Spitzmarke, Titel und Daten nehmen die Satzbreite und stehen darunter auf Mitte.

#4 · Kolumnentitel mit dem Abschnitt auf der rechten Seite

script.js · Zeilen 148–161im vollständigen Code
const head = (id, content, parity, edge, x, extra = {}) => ({
  kind: 'text', id, content, parity, pages: 'body', fontFamily: LABEL, fontSize: pt(7.5),
  fontWeight: 500, letterSpacing: pt(1.2), textTransform: 'uppercase', color: col('muted'),
  placement: { anchor: { to: 'page', edge }, offset: { x: mm(x), y: mm(13) } }, ...extra });
const folio = { fontFamily: TEXT, fontSize: pt(9.5), fontWeight: 400, letterSpacing: pt(0),
  color: col('ink') };
const header = { elements: [
  head('verso-folio', '{pageNumber}', 'even', 'top-left', OUTER, folio),
  head('verso-title', '{title}', 'even', 'top-left', OUTER + 8),
  head('recto-title', '{firstMark.h2}', 'odd', 'top-right', -(OUTER + 8)),
  head('recto-folio', '{pageNumber}', 'odd', 'top-right', -OUTER, folio),
] };
const footer = { elements: [head('drop-folio', '{pageNumber}', 'all', 'top', 0, {
  ...folio, pages: 'opener', placement: at('container', 'top', 8) })] };

Die linke Seite trägt den Buchtitel, die rechte den laufenden Abschnitt, {firstMark.h2}: Seite 3 zeigt The Bean-Field, 1845. Die Seitenzahlen stehen in Alegreya und behalten ihre Mediävalziffern.

Seite 2: Die Mediävalziffern der Hausrechnung sind alle gleich breit, und die Cent stehen bis zur Summe untereinander.

Das ganze Rezept

Sandbox
// ═══ Postext Cookbook · Nº 176 · Old-style, lining and tabular figures ═══════════════
// https://postext.dev/en/cookbook/old-style-and-tabular-figures
// Code: MIT · Text: H. D. Thoreau, Walden (1854, public domain) · Vignette: 1854 title page (PD)
// Fonts: Alegreya, Alegreya SC, Alegreya Sans (SIL OFL 1.1) · Needs postext ≥ 1.65.0
// Thoreau's accounts from Walden. Each text style asks Alegreya for one kind of figures:
// old-style in the prose, lining in the small-capital headings, tabular in the accounts.
import {
  buildDocumentWithFonts, renderPageToCanvas, registerResourceImage, defaultResourceTypes,
} from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';

const LANG = 'en'; // @lang: the language of the sample document ('en' | 'es')
const RECIPE = 'old-style-and-tabular-figures';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
const palette = {
  ink: '#221e1a', // text: a warm near-black
  accent: '#7d3a1f', // walnut: headings, kicker, rules of the opener
  rule: '#8a7f73', // the light rules of the accounts
  muted: '#6b6158', // running heads, the colophon
  paper: '#ffffff',
};
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = [
  ...Object.entries(palette).map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } })),
  { id: 'main-color', name: 'accent (defaults)', value: { hex: palette.accent, model: 'hex' } },
];
const TEXT = 'Alegreya', CAPS = 'Alegreya SC', LABEL = 'Alegreya Sans';
const TRIM = [140, 216], INNER = 19, OUTER = 16; // mm: a trade paperback
const MEASURE = TRIM[0] - INNER - OUTER, VIGNETTE = 50; // mm
const LEAD = 14.5; // pt: the body leading, the grid the headings keep to

// #region answer: one figure style per text style
// Alegreya's own figures are old-style, so the prose asks for none: the cut Fontsource
// serves has no onum, and 'oldstyle' would change nothing (see the write-up).
const bodyText = {
  fontFamily: TEXT, fontSize: pt(10.8), lineHeight: pt(LEAD), color: col('ink'),
  boldColor: col('ink'), italicColor: col('ink'), referenceColor: col('ink'),
  textAlign: 'justify', firstLineIndent: mm(4.5), indentAfterHeading: false,
  hyphenation: { enabled: true }, optimalLineBreaking: true,
  avoidWidows: true, avoidOrphans: true, avoidRunts: true,
};
// Small capitals take lining figures (lnum), at the height of the capitals around them.
const section = { level: 2, fontFamily: CAPS, fontSize: pt(12.5), lineHeight: pt(LEAD),
  fontWeight: 400, letterSpacing: pt(0.6), color: col('accent'), figureStyle: 'lining',
  marginTop: pt(LEAD), marginBottom: pt(0) };
// The accounts: every figure on one width (tnum), so the cents stand in columns.
// 'tabular' keeps the font's form, old-style; 'lining-tabular' would set them at cap height.

Das zusammengesetzte script.js läuft unverändert: Fügen Sie es in das Modulskript einer beliebigen Seite ein, oder öffnen Sie das Rezept auf CodePen. Ordner des Rezepts auf GitHub ↗ (öffnet sich in einem neuen Tab)

Varianten

#Die Rechnungen in Versalziffern setzen

Ein Kontobuch oder eine Preisliste in einem modernen Buch setzt die Ziffern oft auf Versalhöhe.

-  figureStyle: 'tabular', bodyFontFamily: TEXT, bodyFontSize: pt(9.8), bodyColor: col('ink'),
+  figureStyle: 'lining-tabular', bodyFontFamily: TEXT, bodyFontSize: pt(9.8), bodyColor: col('ink'),

#Die Seitenzahlen in Versalziffern setzen

Seitenzahlen in Versalziffern passen zu Kolumnentiteln in Großbuchstaben.

-const folio = { fontFamily: TEXT, fontSize: pt(9.5), fontWeight: 400, letterSpacing: pt(0),
+const folio = { fontFamily: TEXT, fontSize: pt(9.5), fontWeight: 400, letterSpacing: pt(0),
+  figureStyle: 'lining',

Häufige Fehler

  • Die latin-Dateien, die Fontsource ausliefert, lassen onum oft weg: Lora, EB Garamond, Source Serif 4, Crimson Pro, Newsreader und Literata behalten nur pnum und tnum. Mit diesen Dateien ändert figureStyle: 'oldstyle' nichts, und der Text behält Versalziffern. Wählen Sie eine Schrift, deren eigene Ziffern Mediävalziffern sind, etwa Alegreya, Gelasio oder Cormorant Garamond, die lnum für Überschriften mitbringen, oder laden Sie die vollständigen Dateien der Schriftgießerei.
  • Ein $ im Markdown oder in einer Tabellenzelle öffnet eine Formel. Schreiben Sie \$14.72½ im Text und \$ in einer Zelle.

Nachweise

Text
  • The accounts and the passages around them from “Economy,” the first chapter of Walden; or, Life in the Woods (Boston: Ticknor and Fields, 1854) · Henry D. Thoreau · gemeinfrei
  • The headnote, and the Spanish translation of the passages and the accounts · Ignacio Ferro · CC BY 4.0
Bilder
Schriften
Alegreya (SIL OFL 1.1) · Alegreya SC (SIL OFL 1.1) · Alegreya Sans (SIL OFL 1.1)
SandboxPDF