Em poucas palavras
Uma pequena edição das contas domésticas que Thoreau publicou em Walden. Os números do texto são pequenos como minúsculas, os anos dos títulos têm a altura das maiúsculas e as somas das contas se alinham em coluna.
O que você vai compor
Uma pequena edição das contas que Thoreau publicou no primeiro capítulo de Walden: quanto lhe custou a casa, quanto rendeu o campo de feijão, o que comeu em oito meses. Ela é composta numa página de 140 × 216 mm na família Alegreya, com a gravura de 1854 da cabana na abertura. Os algarismos mudam conforme a função. Na prosa, March, 1845 e $13.34 vão em algarismos de estilo antigo, que sobem e descem como as minúsculas, e as datas não saltam da linha. Os títulos são versaletes, e seus anos têm a altura das maiúsculas. Nas contas todos os algarismos têm a mesma largura, e os centavos de treze linhas de tábuas, sarrafos e pregos ficam um embaixo do outro até o total.
Esta receita responde a
- Como componho algarismos de estilo antigo no texto, algarismos alinhados nos títulos e algarismos tabulares nas tabelas?
- Como componho ilustrações sem numeração: ornamentos, vinhetas, logotipos?
A resposta curta
// 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),
};
Ingredientes
- Funcionalidades
- Estilos de algarismosEstilo de tabelaTabelas a partir de dadosTipos de recurso personalizadosPosicionamento de figurasAberturas desenhadasImagens nos designs de páginaAtributos de títuloCabeços por seçãoCabeços e fóliosMargens espelhadasEstilos de parágrafoPaleta de cores semânticaExportação para PDFFontes incorporadas ao PDF
- Também usa
- Figuras exatamente aquiFigura e Tabela no seu idiomaCabeços por tipo de páginaFiguras e tabelas como recursos
- Tipografia
- Alegreya, Alegreya SC, Alegreya Sans (SIL OFL 1.1)
- Materiais
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), domínio público)
Preparo
#1 · Um estilo de algarismos por estilo de texto
O código deste passo é a resposta curta, mais acima. figureStyle pede à fonte de um estilo seus algarismos OpenType (estilos de algarismos). O corpo não pede nada, porque os algarismos próprios da Alegreya já são de estilo antigo e proporcionais: o 1 tem 342 unidades e o 0, 533. Os títulos de segundo nível pedem à Alegreya SC 'lining', seus algarismos lnum, da altura das maiúsculas ao redor. O estilo de tabela pede 'tabular', o tnum da fonte: os algarismos mantêm a forma de estilo antigo e ficam todos com a mesma largura, 450 unidades, e uma coluna de preços se lê de cima a baixo. Com 'lining-tabular' eles ficariam na altura das maiúsculas (veja “Variações”).
#2 · As contas são tabelas de cinco colunas
// 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'))]));
As contas de Thoreau ficam em TSV em content.accounts.en.md, um bloco por conta, e a edição espanhola traduz os itens e troca o ponto decimal pela vírgula sem mexer no código. Cada linha tem o item, o cifrão, o valor, uma fração e uma observação. As metades e os quartos têm coluna própria: ½ tem 713 unidades e ¾, 689, mais que um algarismo tabular, e a Alegreya não tem espaço de algarismo para completar os outros valores. Um total é feito de células de cabeçalho, então groupRules traça um fio fino acima dele, como o impressor de Thoreau traçava uma linha antes de In all. O cifrão se escreve \$, porque um $ sozinho abre uma fórmula numa célula, como no texto. O tipo de recurso account não tem número nem prefixo de legenda, e sua colocação padrão é 'here': cada conta fica onde a frase de Thoreau a apresenta.
#3 · A abertura declara seus próprios algarismos
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) } } },
] } };
Um texto de design define a própria família, então os algarismos do corpo não chegam até ele. Concord, 1845–1847 está em Alegreya SC e pede 'lining' por conta própria, como os títulos. A vinheta é a gravura da folha de rosto de 1854, recortada e ajustada para preto sobre branco; o antetítulo, o título e as datas tomam a largura da mancha e se centralizam embaixo dela.
#4 · Cabeços com a seção na página ímpar
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) })] };
A página par traz o título do livro, e a ímpar, a seção em curso, {firstMark.h2}: a página 3 diz The Bean-Field, 1845. Os fólios vão em Alegreya e mantêm os algarismos de estilo antigo.

A receita completa
// ═══ 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.
O script.js montado funciona como está: cole-o como script de módulo em qualquer página ou abra a receita no CodePen. Pasta da receita no GitHub ↗ (abre em uma nova aba)
Variações
#Componha as contas em algarismos alinhados
Um livro-caixa ou uma lista de preços num livro moderno costuma pôr os algarismos na altura das maiúsculas.
- figureStyle: 'tabular', bodyFontFamily: TEXT, bodyFontSize: pt(9.8), bodyColor: col('ink'),
+ figureStyle: 'lining-tabular', bodyFontFamily: TEXT, bodyFontSize: pt(9.8), bodyColor: col('ink'),#Componha os fólios em algarismos alinhados
Fólios em algarismos alinhados combinam com cabeços em maiúsculas.
-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',Erros comuns
- Os arquivos latin que a Fontsource serve muitas vezes deixam
onumde fora: Lora, EB Garamond, Source Serif 4, Crimson Pro, Newsreader e Literata só mantêmpnumetnum. Com esses arquivos,figureStyle: 'oldstyle'não muda nada e o texto continua com algarismos alinhados. Escolha uma fonte cujos algarismos próprios sejam de estilo antigo, como Alegreya, Gelasio ou Cormorant Garamond, que trazemlnumpara os títulos, ou carregue os arquivos completos da fundição. - Um
$no Markdown ou numa célula abre uma fórmula em linha. Escreva\$14.72½no texto e\$numa célula.
Créditos
- Receita
- Ignacio Ferro
- Texto
- 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 · domínio público
- The headnote, and the Spanish translation of the passages and the accounts · Ignacio Ferro · CC BY 4.0
- Imagens
- 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) · domínio público
- Fontes
- Alegreya (SIL OFL 1.1) · Alegreya SC (SIL OFL 1.1) · Alegreya Sans (SIL OFL 1.1)
- Código
- MIT, como o Postext
Editar este texto ↗ (abre em uma nova aba)Pasta da receita no GitHub ↗ (abre em uma nova aba)


