Aller au contenu principal
Recette numéro 180

Recettes · Chapitre 2 · Caractères et texte

Surlignages par couleur dans un livre de lectures

Un livre de lectures d’histoire dont les mots clés portent trois couleurs (vert pour les termes, ambre pour les dates, bleu pour les noms) tirées de markStyles.

  • Exemple en anglais : pas encore d’édition française
  • Format 170 × 240 mm
  • 1 colonne
  • Source Serif 4 10,5/14,5
  • Source Sans 3
  • 4 pages
  • Niveau
  • Postext 1.65.0
  • Mis en page en 127 ms
  • 164 lignes de code

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

script.js · lignes 37–52dans le code complet
// :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

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

script.js · lignes 14–29dans le code complet
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

script.js · lignes 56–81dans le code complet
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é

script.js · lignes 85–106dans le code complet
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

Sandbox
// ═══ 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 band

Erreurs 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 markStyles ne 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

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)
Sandbox