本文へスキップ
レシピ番号180

レシピ集 · 第2章 · 文字と本文

学習用読本の色分けハイライト

歴史の読本で、キーワードを3色に塗り分けます。用語は緑、年代は琥珀色、人名と地名は青。3つのスタイルはmarkStylesで定義し、パレットに結び付けます。

このページの内容

1ページ(全4ページ)

  • 英語の見本:日本語版はまだありません
  • 仕上がり170 × 240 mm
  • 1段
  • Source Serif 4 10.5/14.5
  • Source Sans 3
  • 4ページ
  • レベル
  • Postext 1.65.0
  • 組版時間127 ms
  • コード164行

かんたんな説明

印刷の歴史を扱う学校向けの読み物です。用語は緑、年代は琥珀色、人や場所は青でハイライトされ、最初のページの凡例がそれぞれの色の意味を説明します。

できあがり

学校向けの歴史読本『Readings in Early Modern History』のある単元の「読み物2」です。1450年から1550年にかけて印刷術がマインツからヨーロッパへ広がった経緯を、170 × 240 mmのページ4枚で扱います。編集者は熱心な生徒のように本文に印を付けていて、その色の約束は本全体で変わりません。用語は緑の帯、年代は琥珀色、人物と場所は淡い青の上に載ります。タイトルの下の凡例はその3色そのものを使って約束を説明し、最後のページの用語集は各項目を緑の用語で始めます。印はふつうの文字の下に敷いた帯なので、改行もハイフネーションも両端揃えも、帯がないときと同じです。

このレシピが答える質問

  • 学習用の文章のキーワードを、意味ごとに色を分けて(用語・年代・人名)ハイライトするには?

手短な答え

script.js · 37〜52行コード全体で見る
// :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' })),
];

材料

種類
Source Serif 4, Source Sans 3 (SIL OFL 1.1)
素材
  • press-1400.jpg
  • The printing workshop on the opening page, a painting (Generated With Diffusion Models, オリジナル)

作り方

#1 · 語の種類ごとにひとつのスタイル

コードは上の手短な答えにあります。markStylesで名前付きのスタイルを3つ宣言し、本文の各ハイライトがそのひとつを選びます。:mark[Johann Fust]{style="name"}、:mark[1455]{style="date"}、:mark[colophon]{style="term"}のように書きます(ハイライト)。各スタイルは意味を表すので(nameは編集時に見える名前)、Markdownにはその語に印を付けた理由が残り、何色かは残りません。スタイルの色を変えれば、本のすべての年代がいっしょに変わります。帯の端は角のままで、postext 1.52からこれが既定です(ハイライトのスタイル)。蛍光ペンの線は端が角張っていて、角を丸めた帯はチップに見えてしまいます。

#2 · パレットの3つの淡い色

script.js · 14〜29行コード全体で見る
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' } },
];

3本の帯は、文字色やアクセント色と同じくパレットの項目です。Sandboxでこの本を開いた人は、色見本をひとつ変えるだけで約束の色を変えられます。色は囲みの地色に近い明るさまで淡くしてあり、上の文字は12.6:1以上のコントラストを保ちます。3色が1行の中で隣り合っても見分けられます。3ページの「In 1517 Martin Luther」がその例です。ハイライトは場所を取りません。paddingXは語句の横の空白へ0.12 em伸び、paddingBottomは帯をディセンダーの下まで下ろします。どちらも、もともとある空きに塗られます。

#3 · 扉:タイトルの上の絵

script.js · 56〜81行コード全体で見る
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' } } },
    ],
  },
};

レベル1の見出しはデザインを印刷します。絵はページに固定してあるので、上と左右の端まで裁ち落としになり、大きさは170 × 96 mm、fit: 'cover'で収めます。見出しラベルとリード文は見出し行の属性から取り(見出しの属性)、凡例はふつうの:::calloutで、そのリストの各項目が3つのハイライトで始まります。minHeightが扉の深さを決めるので、タイトルが長くても短くても凡例は同じ行から始まります。

#4 · 偶数・奇数ページで分ける柱

script.js · 85〜106行コード全体で見る
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) } },
  })],
};

偶数ページにはシリーズ名、奇数ページには読み物のタイトルを入れます。どちらもparityで振り分け、pages: 'body'で扉には出しません(テキスト要素)。扉のノンブルは下に置きます。

レシピの全体

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 = [

組み立てたscript.jsはそのまま動きます。任意のページのモジュールスクリプトに貼り付けるか、レシピをCodePenで開いてください。 GitHub上のレシピのフォルダー ↗ (新しいタブで開きます)

アレンジ

#帯の端を丸める

文字サイズの5分の1の半径にすると、フェルトペンのような柔らかい端になります。

-  // 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

#行ごとに帯を完結させる

decorationBreak: 'clone'にすると、行をまたぐハイライトは各行の部分の両端に余白が付きます。3ページで「pamphlets」が「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

よくあるつまずき

  • 色だけの区別は白黒コピーで消えます。そして多くの読み物は、コピーされて教室に届きます。この用語集では用語を太字にもしています。読者がページをコピーするなら、3種類のうちひとつに色以外の目印も付けてください。
  • markStylesで宣言していないスタイルidは最初のスタイルになり、ページ上にはエラーが出ません(Sandboxは指摘します)。idは短くし、本文での綴りを確かめてください。

クレジット

レシピ
Ignacio Ferro
本文
  • The reading, its key, the review questions and the colophon · Ignacio Ferro · CC BY 4.0
画像
  • The printing workshop on the opening page, a painting · Generated With Diffusion Models · オリジナル
フォント
Source Serif 4 (SIL OFL 1.1) · Source Sans 3 (SIL OFL 1.1)
Sandbox