En bref
Une lecture scolaire sur l’histoire de l’imprimerie. Les termes clés sont surlignés en vert, les dates en ambre, les personnes et les lieux en bleu, et une légende en première page dit ce que veut dire chaque couleur.
Ce que vous allez composer
La lecture 2 d’une unité d’un livre scolaire d’histoire, Readings in Early Modern History : quatre pages sur la façon dont l’imprimerie a gagné l’Europe depuis Mayence entre 1450 et 1550, sur une page de 170 × 240 mm. Les éditeurs ont marqué le texte comme le ferait un bon élève, avec un code qui reste le même dans tout le livre : les termes clés sur une bande verte, les dates sur de l’ambre, les personnes et les lieux sur du bleu pâle. Une légende sous le titre explique le code avec les trois couleurs elles-mêmes, et le glossaire de la dernière page ouvre chaque entrée sur son terme vert. Les marques sont des bandes sous du texte ordinaire : les lignes se coupent, se divisent et se justifient comme si elles n’étaient pas là.
Cette recette répond à
- Comment surligner les mots clés d’un texte d’étude avec des couleurs qui ont chacune un sens (termes, dates, noms) ?
La réponse courte
// :mark[Mainz]{style="name"} in the text picks a style by id. The band is painted under
// words that stay ordinary text, so the lines break, hyphenate and justify as if the
// mark were not there, and a mark that runs over a line end gets a band on each line.
const band = (id, name) => ({
id, name,
background: col(id), // pale enough for ink at full contrast on top
color: col('ink'), // the words keep the colour of the text
// borderRadius: 0 is the default (square ends, as a highlighter pen leaves them)
paddingX: em(0.12), // the band reaches a little past the first and the last letter
paddingTop: em(0.04), paddingBottom: em(0.1), // and down past the descenders
});
const markStyles = [
band('term', t({ en: 'Key term', es: 'Término clave' })),
band('date', t({ en: 'Date', es: 'Fecha' })),
band('name', t({ en: 'Name', es: 'Nombre' })),
];
Ingrédients
- Fonctionnalités
- SurlignagesEncadrésPalette de couleurs sémantiqueOuvertures composéesImages dans les maquettes de pageAttributs de titreTitres courants et foliosTitres courants selon le rôle de la pageMarges en miroirStyles de paragrapheVeuves, orphelines et fins de paragraphe trop courtes
- Utilise aussi
- Bibliographies et glossairesFigure et Tableau dans votre langueTypes de ressource personnalisésFigures et tableaux comme ressources
- Typographie
- Source Serif 4, Source Sans 3 (SIL OFL 1.1)
- Ressources
press-1400.jpg- The printing workshop on the opening page, a painting (Generated With Diffusion Models, original)
Préparation
#1 · Un style par sorte de mot
Le code est la réponse courte plus haut. markStyles déclare trois styles nommés, et le texte en choisit un pour chaque marque : :mark[Johann Fust]{style="name"}, :mark[1455]{style="date"}, :mark[colophon]{style="term"} (surlignages). Chaque style dit ce qu’il signifie (name est ce que voit la personne qui édite) : le Markdown garde la raison pour laquelle un mot est marqué, pas la couleur qu’il porte. Changez la couleur d’un style, et toutes les dates du livre changent avec elle. Les extrémités sont droites, comme par défaut depuis postext 1.52 (styles de surlignage) : un surligneur laisse des bouts droits, et une bande arrondie se lit comme une pastille.
#2 · Trois teintes de la palette
const palette = {
ink: '#1f1c19', // text: a warm near-black
accent: '#8a3220', // kickers, rules, numbers: an iron-gall red
tint: '#f5f0e7', // the key's background
rule: '#d3cabc', // hairlines
muted: '#6b645b', // running heads, colophon
paper: '#ffffff',
term: '#cce8c8', // key terms: a pale green
date: '#fbe0a1', // dates: amber
name: '#cfe0f4', // people and places: a pale blue
};
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' } },
];
Les trois bandes sont des entrées de la palette, comme l’encre et l’accent : qui ouvre le livre dans le Sandbox peut changer le code depuis une seule nuance. Elles sont pâles, d’une clarté proche du fond de l’encadré, et le texte posé dessus garde un contraste de 12,6:1 ou plus ; les trois restent distinctes quand elles se suivent sur une ligne, comme à « In 1517 Martin Luther » en page 3. Une marque ne prend pas de place : paddingX entre de 0,12 em dans l’espace à côté de la phrase et paddingBottom descend la bande sous les jambages, les deux peints dans un espace qui existait déjà.
#3 · L’ouverture : une peinture au-dessus du titre
const opener = {
enabled: true,
minHeight: mm(122), // the floor of the opener: the key starts on the same line
marginBottom: pt(0),
slot: {
elements: [
{ kind: 'image', id: 'press', resourceId: 'press', fit: 'cover',
placement: { anchor: { to: 'page', edge: 'top-left' },
size: { width: mm(170), height: mm(96) } } },
{ kind: 'text', id: 'kicker', content: '{attr.kicker}', fontFamily: SANS,
fontSize: pt(8.5), fontWeight: 700, letterSpacing: pt(1.6),
textTransform: 'uppercase', color: col('accent'), align: 'left',
placement: { anchor: { to: 'container', edge: 'top-left' },
offset: { x: mm(0), y: mm(82) } } },
{ kind: 'text', id: 'title', content: '{titleText}', fontFamily: SERIF,
fontSize: pt(26), lineHeight: 1.08, fontWeight: 700, color: col('ink'), align: 'left',
placement: { anchor: { to: '#kicker', edge: 'below' }, offset: { x: mm(0), y: mm(2) },
size: { width: mm(126), height: 'auto' } } },
{ kind: 'text', id: 'standfirst', content: '{attr.standfirst}', fontFamily: SERIF,
italic: true, fontSize: pt(10.5), lineHeight: LEAD / 10.5, color: col('ink'),
align: 'left',
placement: { anchor: { to: '#title', edge: 'below' }, offset: { x: mm(0), y: mm(3) },
size: { width: mm(118), height: 'auto' } } },
],
},
};
Le titre de premier niveau imprime un design. La peinture est ancrée à la page : elle déborde à fond perdu en haut et des deux côtés, 170 sur 96 mm, avec fit: 'cover'. Le surtitre et le chapeau viennent d’attributs de la ligne du titre (attributs de titre), et la légende suit sous la forme d’un :::callout ordinaire dont les éléments de liste commencent par les trois marques. minHeight fixe la profondeur : la légende commence sur la même ligne quelle que soit la longueur du titre.
#4 · Titres courants selon la parité
const head = (id, content, parity, edge, x, extra = {}) => ({
kind: 'text', id, content, parity, pages: 'body',
fontFamily: SANS, fontSize: pt(7.5), fontWeight: 600, letterSpacing: pt(1.2),
textTransform: 'uppercase', color: col('muted'),
placement: { anchor: { to: 'page', edge }, offset: { x: mm(x), y: mm(13) } },
...extra,
});
const folio = { fontWeight: 700, color: col('ink') };
const header = {
elements: [
head('verso-folio', '{pageNumber}', 'even', 'top-left', OUTER, folio),
head('verso-title', '{title}', 'even', 'top-left', OUTER + 9),
head('recto-title', '{chapterTitle}', 'odd', 'top-right', -(OUTER + 9)),
head('recto-folio', '{pageNumber}', 'odd', 'top-right', -OUTER, folio),
],
};
const footer = {
elements: [head('drop-folio', '{pageNumber}', 'all', 'top', 0, {
...folio, pages: 'opener',
placement: { anchor: { to: 'container', edge: 'top' }, offset: { x: mm(0), y: mm(9) } },
})],
};
La page paire porte le titre de la collection et la page impaire celui de la lecture, filtrés par parity et tenus hors de l’ouverture par pages: 'body' (éléments de texte). L’ouverture porte son folio en pied de page.
La recette complète
// ═══ Postext Cookbook · Nº 180 · Colour-coded highlights in a study reader ════════
// https://postext.dev/en/cookbook/colour-coded-study-highlights
// Code: MIT · Text: original (CC BY 4.0) · Picture: painting made for the recipe
// Fonts: Source Serif 4, Source Sans 3 (SIL OFL 1.1) · Needs postext ≥ 1.65.0
import {
buildDocumentWithFonts, renderPageToCanvas, registerResourceImage, defaultResourceTypes,
} from 'https://esm.sh/postext';
const LANG = 'en'; // @lang: the language of the sample document ('en' | 'es')
const RECIPE = 'colour-coded-study-highlights';
// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: semantic colours, three of them for the highlighter
const palette = {
ink: '#1f1c19', // text: a warm near-black
accent: '#8a3220', // kickers, rules, numbers: an iron-gall red
tint: '#f5f0e7', // the key's background
rule: '#d3cabc', // hairlines
muted: '#6b645b', // running heads, colophon
paper: '#ffffff',
term: '#cce8c8', // key terms: a pale green
date: '#fbe0a1', // dates: amber
name: '#cfe0f4', // people and places: a pale blue
};
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' } },
];
// #endregion
const OUTER = 20; // outer margin in mm: the running heads align to it
const LEAD = 14.5; // body leading in pt
const SANS = 'Source Sans 3';
const SERIF = 'Source Serif 4';
// #region answer: three highlight styles, one per kind of word, linked to the palette
// :mark[Mainz]{style="name"} in the text picks a style by id. The band is painted under
// words that stay ordinary text, so the lines break, hyphenate and justify as if the
// mark were not there, and a mark that runs over a line end gets a band on each line.
const band = (id, name) => ({
id, name,
background: col(id), // pale enough for ink at full contrast on top
color: col('ink'), // the words keep the colour of the text
// borderRadius: 0 is the default (square ends, as a highlighter pen leaves them)
paddingX: em(0.12), // the band reaches a little past the first and the last letter
paddingTop: em(0.04), paddingBottom: em(0.1), // and down past the descenders
});
const markStyles = [
Le script.js composé s’exécute tel quel : collez-le dans le script de module de n’importe quelle page, ou ouvrez la recette sur CodePen. Dossier de la recette sur GitHub ↗ (s’ouvre dans un nouvel onglet)
Variantes
#Arrondir les bouts des bandes
Un rayon d’un cinquième du corps donne les bouts adoucis d’un feutre.
- // borderRadius: 0 is the default (square ends, as a highlighter pen leaves them)
+ borderRadius: em(0.2), // soft ends, as a felt-tip pen leaves them#Donner à chaque ligne sa propre bande
Avec decorationBreak: 'clone', une marque qui passe à la ligne reçoit la marge aux deux bouts de chaque morceau, comme en page 3, où « pamphlets » se coupe après « pam- ».
paddingX: em(0.12), // the band reaches a little past the first and the last letter
+ decorationBreak: 'clone', // each line piece gets a whole bandErreurs fréquentes
- La couleur seule ne survit pas à une photocopie en noir et blanc, qui est la façon dont beaucoup de lectures arrivent en classe. Le glossaire met en plus les termes en gras ; si vos lecteurs photocopient les pages, donnez à l’une des trois sortes un second signe qui lui soit propre.
- Un identifiant de style que
markStylesne déclare pas prend le premier style, sans erreur sur la page (le Sandbox le signale). Gardez des identifiants courts et vérifiez leur orthographe dans le texte.
Crédits
- Recette
- Ignacio Ferro
- Texte
- The reading, its key, the review questions and the colophon · Ignacio Ferro · CC BY 4.0
- Images
- The printing workshop on the opening page, a painting · Generated With Diffusion Models · original
- Polices
- Source Serif 4 (SIL OFL 1.1) · Source Sans 3 (SIL OFL 1.1)
Modifier ce texte ↗ (s’ouvre dans un nouvel onglet)Dossier de la recette sur GitHub ↗ (s’ouvre dans un nouvel onglet)


