# 配置：页眉与页脚

> 每页顶部和底部印出的内容：带占位符的文字、线条、方框和图像，按奇偶页分别设置，以及每个元素的位置

- HTML版本: https://postext.dev/zh/docs/configuration-headers-footers
- 最后更新: 2026-10-16
- 阅读时间: 21分钟
- 其他语言: [en](https://postext.dev/en/docs/configuration-headers-footers.md), [es](https://postext.dev/es/docs/configuration-headers-footers.md), [ca](https://postext.dev/ca/docs/configuration-headers-footers.md), [de](https://postext.dev/de/docs/configuration-headers-footers.md), [fr](https://postext.dev/fr/docs/configuration-headers-footers.md), [it](https://postext.dev/it/docs/configuration-headers-footers.md), [pt](https://postext.dev/pt/docs/configuration-headers-footers.md), [ja](https://postext.dev/ja/docs/configuration-headers-footers.md), [ar](https://postext.dev/ar/docs/configuration-headers-footers.md)

## 简单来说

本页讲每页顶部和底部印出的内容。页眉或页脚里可以放页码、书名或章名、一条线、一个方框或一张小图。左页和右页可以显示不同的内容。每个元素可以放在左边、中间或右边，也可以放在正文旁边的页边里。页眉和页脚位于页边距之内，所以不会让正文区域变小。

## 页眉与页脚

`header`和`footer`属性控制每一页的页眉和页脚槽位。页眉和页脚渲染在**现有的页边距之内**：它们不另外占用空间，也不会缩小内容区。

**容器框。** 锚定到`'container'`的元素放在正文与裁切边之间的页边带里，宽度等于内容区的宽度。页眉容器从**裁切上边**一直延伸到正文顶部；页脚容器从正文底部一直延伸到**裁切下边**。因此，页眉的`top-*`锚点和页脚的`bottom-*`锚点从裁切边量起，而页眉的`bottom-*`锚点和页脚的`top-*`锚点从正文边缘量起。容器从不包含出血区或裁切标记带，所以无论`page.cutLines`开还是关，页眉或页脚在裁切后的页面上都落在同一位置。要超出内容区的宽度或伸进出血区，就锚定到`'page'`（裁切框）或`'bleed'`。

槽位使用统一的**设计槽位**模型：每个元素都有一个`placement`，其中包含一个`anchor`（锚定到容器，或通过`#id`锚定到另一个元素）、一个可选的`offset`和一个可选的`size`。旧版的平铺字段`align`、`marginFromBody`、`marginFromEdge`和`width: 'full'`在输入时仍然接受，并会自动迁移成新的结构；对应的新结构写法见下文。

每个槽位保存一组**文本**、**线条**和**方框**元素。数组顺序就是绘制顺序（第一个元素最先绘制，最后一个元素画在最上层）。无论锚点怎么写，这一点都成立：元素可以锚定到排在它后面的元素（`anchor.to: '#ttl'`），所以背景方框可以排在最前面，同时仍按它衬在其后的文本来定位。

**内置默认值。** 当`header`或`footer`为`undefined`时，postext会使用一套合理的内置默认设置，而不是留一个空槽位：

- **默认页眉：** 奇数页右对齐显示`{title}`，偶数页左对齐显示`{chapterTitle}`，另加一条通宽线条；全部使用调色板的主色，Open Sans 8pt/600，`marginFromBody`为`16pt`（文本）/`13pt`（线条）。
- **默认页脚：** 每页居中显示`{pageNumber}`，使用调色板的主色，Open Sans 8pt/600，`marginFromBody`为`16pt`。

要关闭内置默认值，设置`header: { elements: [] }`（或`footer: { elements: [] }`）。显式的空`elements`数组会保留为“没有元素”；只有`undefined`才会触发默认值。

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `elements` | `HeaderFooterElement[]` | 为`undefined`时使用内置默认值；`[]`表示禁用 | 文本元素和线条元素的有序列表。 |

### 文本元素

文本元素渲染一个模板字符串，并替换其中的占位符。占位符使用`{name}`语法；`{{`和`}}`输出字面的花括号。

下表中的默认值是你自己添加的文本元素的默认值。上文**内置默认值**中介绍的内置页眉和页脚是现成的元素，带有各自的取值（调色板主色的Open Sans 8pt/600），并非元素的默认值。

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `kind` | `'text'` | — | 类型判别字段。 |
| `id` | `string` | — | 稳定的id，在槽位内唯一。其他元素通过`anchor.to: '#id'`锚定到它。沙盒在创建元素时会自动分配一个。 |
| `content` | `string` | `''` | 模板字符串。支持下面列出的占位符，另外还支持`{attr.<key>}`：写在当前章H1行上的属性（`# Title {author="I. Zango"}`）。缺失的属性解析为空字符串，不发出警告。换行符，或者写在模板或属性值中的两个字符`\n`，无论`overflow`取什么值，都会另起一行。占位符从文档复制来的文本（标题、frontmatter字段）按原样输出：在那里只有真正的换行（例如标题中的换行）才会另起一行。 |
| `align` | `'left' \| 'center' \| 'right' \| 'justify' \| 'start' \| 'end'` | `'center'` | 各行在元素方框内的水平对齐方式。`'justify'`会拉宽每一段中除最后一行以外所有折行的词间距，让行填满方框；首字下沉旁边的行填满它旁边的空间。开启`hyphenate`时，放不进两端对齐行剩余空间的词还会在音节处断开来填满这一行。段落的最后一行、没有可拉伸空格的行，以及不折行的文本都齐左排。两端对齐的文本按段落逐段排版，所以段落之间的多个空行算作一个。Canvas和PDF把每个词放在版面给定的位置；HTML则用`word-spacing`加宽空格。`'start'`和`'end'`跟随文本的`direction`：对从右到左的文本即右边和左边。`'left'`和`'right'`是方框自身的两侧；在从右到左页面的文字流中排出的设计（章首区段、标题设计）里，文字流是镜像的，所以它们就是起始侧和结束侧，与正文相同。 |
| `direction` | `'ltr' \| 'rtl' \| 'auto'` | 文档的方向 | 文本的基本方向：决定中性字符的归属、一行中各段的顺序，以及`'start'`和`'end'`指哪一侧。`'auto'`读取解析后文本的第一个强方向字母，没有时取文档的[`direction`](https://postext.dev/zh/docs/configuration-language.md#文本方向)。阿拉伯文和希伯来文的片段无论基本方向如何都从右到左读。含阿拉伯字母的文本从不加字距（整段文本的`letterSpacing`都被忽略），折行或截断时也从不切开其中的词；比方框还宽的词会溢出，并报告为`unbreakableWordOverflow`。 |
| `parity` | `'all' \| 'odd' \| 'even'` | `'all'` | 元素出现在哪些页上（按页码奇偶：第1页为奇数页）。 |
| `pages` | `'all' \| 'body' \| 'opener' \| 'part' \| 'blank'` | `'all'` | 元素出现在哪些页面*角色*上，与`parity`组合使用。排版完成后，每一页都会被归为`'blank'`（为奇偶补的页或分隔用的空白页，或没有内容的页）、`'part'`（篇的分隔页）、`'opener'`（第一个块是一个标题，且该级标题通栏或在其前强制分页，即一章的第一页）或`'body'`（其余所有页）。`pages: 'body'`在章首页上隐藏书眉；`pages: 'opener'`只在章首页显示页码。 |
| `fontFamily` | `string` | `'EB Garamond'` | 字体族。 |
| `fontSize` | `Dimension` | `8 pt` | 字号。 |
| `fontWeight` | `number` | `400` | 字重（100–900）。 |
| `italic` | `boolean` | `false` | 是否以斜体渲染。 |
| `color` | `ColorValue` | `#000000` | 文本颜色。 |
| `overflow` | `'wrap' \| 'ellipsis-start' \| 'ellipsis-middle' \| 'ellipsis-end' \| 'clip'` | 标题版式和篇章版式中为`'wrap'`，其余为`'ellipsis-end'` | 文本超出元素可用宽度时引擎如何处理。`'wrap'`把一行折成多行；几种省略号模式让每行保持为一行，并在开头、中间或末尾用`…`截断；`'clip'`在元素的外框处硬性裁掉，不插入任何字符。内容中的换行在所有模式下都有效：省略号模式和裁切模式各自截断或裁切每一行。省略`overflow`的元素取所在位置的默认值：在标题版式（`advancedDesign.slot`）或篇章页（`parts.design`、`parts.versoDesign`）中换行，在书眉、页码或目录的篇行（`toc.parts.design`，行高固定）中以`…`截断。可能排成多行的书眉（如地址）要设为`'wrap'`，章首里必须保持一行的引题则设为省略号。被省略号截断、或在`'clip'`下墨迹超出框的行，会作为`designTextTruncated`内容警告报告，每个元素每页一次（书眉和页码每个元素每章一次）。postext 1.24之前保存的配置（`configVersion`为9或更早）读取时，未设置overflow的标题和篇章文字都按`'ellipsis-end'`处理，页面不会移动。带`dropCap`的文本无论这里怎么设都会折行；设为`'clip'`时，它的行仍会在固定高度方框的边缘被裁掉。`'ellipsis-end'`和`'ellipsis-start'`在词的边界处截断，得到*The history of…*，而不是*The history of th…*；省略号旁边不会紧挨空格或连接性标点（逗号、冒号、破折号、斜杠、左括号）。只有当在词边界截断（去掉这些标点后）保留的内容不到可容纳内容的一半时，才会在词中间截断：一个很长的词，或一个URL（*http://exampl…*，而不是*http…*）。不换行空格或不换行连字符（U+2011，如*MS‑DOS*）不算词边界；`'ellipsis-middle'`可以在任意位置截断，但会去掉两侧的空格。postext 1.4及更早版本中，所有模式都在最后一个放得下的字符处截断，空格也算在内。 |
| `verticalAlign` | `'top' \| 'middle' \| 'bottom'` | `'middle'` | 文本在高于其各行的方框中的位置：固定的`placement.size.height`，或被锚定的相邻元素撑高的方框。当各行比方框高时（固定高度方框里的大号数字、较紧的`lineHeight`），它们会向对齐方式留空的一侧溢出，与CSS flex对齐的做法相同：`'bottom'`让最后一个行框的底边与方框底边对齐，从顶部溢出；`'middle'`在两端均匀溢出；`'top'`从底部溢出。postext 1.4及更早版本中，这样的行无论对齐方式如何都从顶部往下排。`dropCap`会随所在的行一起移动（postext 1.4及更早版本中，`'middle'`或`'bottom'`把行往下移时，首字仍留在方框顶部）。 |
| `lineHeight` | `number \| Dimension` | `1.2` | 元素各行的行距。数字表示`fontSize`的倍数。也接受`Dimension`，与配置中其他所有行距的写法一致：`em` / `rem`同样表示倍数，绝对长度（`pt`、`mm`、`px`…）表示基线之间的距离，`{ value: 15.5, unit: 'pt' }`无论字号多大都设为15.5 pt行距。其他取值（零、负数、格式错误的尺寸）一律使用默认值。postext 1.4及更早版本中，在这里写`Dimension`会让设计的高度无法测量：章首页于是完全不预留空间，连`minHeight`也不预留，正文会排到标题下面去。 |
| `letterSpacing` | `Dimension` | `0` | 字距：每个字符（包括空格）之后额外前进的距离，与CSS的`letter-spacing`完全相同。测得的宽度随之增大，所以自动宽度的方框仍然紧贴文本。字距从不改变字形：字体的合字在Canvas、HTML、EPUB和PDF中都保留（postext 1.27及更早版本中，Canvas和HTML会去掉加字距设计文本的合字，文本因此比测得的宽）。希伯来文与拉丁文一样加字距；只有含阿拉伯字母的文本不加。一行最后一个字符之后的字距不计入对齐，也不计入自动宽度方框，因此加了字距的居中标题按字母居中，右对齐的标题恰好止于边缘，两端对齐行的最后一个字母也抵到边缘（postext 1.4及更早版本中，它们会向左偏半个或一个字距单位，锚定在加字距元素右侧的元素也会多隔开一个字距单位）。负值会收紧字母，36 pt的展示标题常用`{ value: -0.3, unit: 'pt' }`，宽度也同样缩小；Canvas、HTML和PDF的绘制结果一致（postext 1.4及更早版本中，负值会被当作`0`，且不发出警告）。 |
| `textTransform` | `'none' \| 'uppercase'` | `'none'` | 对解析后的文本（包括占位符的值）应用的大小写转换，例如目录中以大写字母排的篇名。 |
| `box` | `ElementBoxStyle` | — | 可选的背景和边框，画在文本后面：`backgroundColor`、`borderColor`、`borderWidth`、`borderRadius`，以及按边设置、让方框超出文本范围的`padding`（字段说明见[方框元素](https://postext.dev/zh/docs/configuration-headers-footers.md#方框元素)）。 |
| `dropCap` | `{ lines, fontFamily, fontWeight, fontSize, color, gap }` | — | 首字下沉：第一个字母放大，排在前`lines`行（默认2行）旁边，使用自己的字体、字重和颜色，与文本相隔`gap`。这个字母立在它所跨最后一行的基线上，`fontSize`默认取让它的顶部与第一行大写字母顶部齐平的字号：文本字号加上`lines` − 1个行距，大写字母高度按字号的0.72计算（大写字母明显高于或低于这个比例的字体，应单独设置`fontSize`）。带首字下沉的文本无论`overflow`怎么设都会折行；设为`'clip'`时，它的行仍会在固定高度方框的边缘被裁掉。与调色板关联的`color`像设计的其他部分一样随篇和节的调色板变化。在标题设计中，这个字母不在文本下方预留空间：它的行框中位于基线以下的部分不会把正文往下推。基线以下还有笔画的字母（许多字体中的Q或J）因此可能伸进设计下方的空间：给标题设一个`marginBottom`来容纳它。postext 1.4及更早版本中，默认字号让这个字母与它所跨的所有行框一样高，所以它的顶部高出第一行；`overflow`不是`'wrap'`时，这个字母会被丢掉且不发出警告；节或篇的调色板不改变它的颜色；与旁边文本一样深的字母还可能把正文推低一条网格线。早先保存的配置保留1.4的字号，并以`fontSize`的形式写明（见[postext 1.4及更早版本写出的文件包](https://postext.dev/zh/docs/configuration-bundles.md#postext-14及更早版本写出的文件包)）。正文中的首字下沉改由段落样式和标题样式设置（见[首字下沉](https://postext.dev/zh/docs/configuration-text.md#首字下沉)），其大写字母高度从字体中测量。 |
| `paragraphIndent` | `Dimension` | `0` | 除第一段外每一段的首行缩进。内容中的换行符，或者来自属性值的文本中的两个字符`\n`，用来分隔段落；连续的换行符算作一个。 |
| `hyphenate` | `boolean` | `false` | 为`true`且文本折行（`overflow: 'wrap'`，或带`dropCap`，后者总是折行）时，经过常规断行后仍然溢出的长词会在音节边界处拆开（使用文档当前的断词语言），并在断开处加软连字符。在两端对齐的文本（`align: 'justify'`）中，放不进一行剩余空间的词还会在最后一个放得下的音节断点处断开，以填满这一行。 |
| `inlineMarks` | `boolean` | `false` | 把解析后的文本（包括占位符的值）当作行内Markdown读取：`**bold**`、`*italic*`、`^superscript^`、`~subscript~`。关闭时，这些标记按原样输出。在标题设计中，`{titleText}`此时保留标题自身的粗体、斜体、上标和下标片段（`*Pneumocystis*`、`CO~2~`），其余字符经过转义，按原样输出（postext 1.19 起）。见[行内标记与描边](https://postext.dev/zh/docs/configuration-headers-footers.md#行内标记与描边)。 |
| `stroke` | `{ width, color?, hollow? }` | — | 围绕字母绘制的描边：`width`（一个`Dimension`，以字形边缘为中心）、`color`（默认取文本颜色；首字下沉取它自己的颜色）和`hollow`（`true`表示只画描边）。见[行内标记与描边](https://postext.dev/zh/docs/configuration-headers-footers.md#行内标记与描边)。 |
| `writingMode` | `'horizontal-tb' \| 'vertical-rl'` | `'horizontal-tb'` | `'vertical-rl'`把文本从上到下排，行从右到左，字符直立：沿切口竖排的书眉，横排章节旁边的竖排标题。见[竖排文本元素](https://postext.dev/zh/docs/configuration-headers-footers.md#竖排文本元素)。 |
| `reserve` | `boolean` | `true` | 仅用于标题设计：该元素是否计入标题在文本流中预留的高度。对可以压在文本下面的装饰（页脚处的印章、边框、侧边色带）设为`false`。见[预留高度](https://postext.dev/zh/docs/configuration-headings.md#保留高度)。页眉、页脚和篇的设计忽略此项。 |
| `marginFromBody` | `Dimension` | `6 pt` | 元素朝向正文的边与正文边缘之间的绝对距离。与其他元素无关。迁移为`placement.offset.y`。 |
| `marginFromEdge` | `Dimension` | `0 pt` | 距所对齐的内容边缘的水平缩进。只在`align`为`'left'`或`'right'`时生效。迁移为`placement.offset.x`。 |
| `placement` | `ElementPlacement` | 由`align` + `marginFromBody` + `marginFromEdge`推导 | 高级定位（见下文）。设置后优先于旧版平铺字段。 |

可用的占位符：

- `{pageNumber}`：当前页从1开始的页码。
- `{totalPages}`：文档的总页数。在逐章排版的书中（沙盒、`buildBundle`），每一章都是一个文档，所以这是该章自己的页数。
- `{bookTotalPages}`：整本书的总页数：所有章，包括空白页。对单独排版的文档，它等于`{totalPages}`。见下文[全书页数](https://postext.dev/zh/docs/configuration-headers-footers.md#全书页数)。
- `{title}`、`{subtitle}`、`{author}`、`{publishDate}`：从`content.metadata`读取的值。未知或为空的元数据渲染为空字符串（并在沙盒中发出警告）。
- `{chapterTitle}`：当前页或之前最近一个H1的文本。[标题样式](https://postext.dev/zh/docs/configuration-styles.md#标题样式)设了`runningChapter: false`的H1（插图页、地图）会被跳过。
- `{chapterTitleAtTop}`、`{chapterNumberAtTop}`：页面顶部所属章的标题和编号；在新章从页面中部其他文本之后开始的页上，它们与`{chapterTitle}`和`{chapterNumber}`不同。见下文[页面顶部所属的章](https://postext.dev/zh/docs/configuration-headers-footers.md#页面顶部所属的章)。
- `{partTitle}`、`{partNumber}`：当前篇的标题和编号（当前页或之前最近的`:::part`页；紧挨在篇页之前为奇偶补的空白页已属于该篇）。第一篇之前为空。
- `{firstMark.<key>}`、`{lastMark.<key>}`：页面的第一个和最后一个检索词：某一级标题（`h1`–`h6`），或某个段落样式的词条。见下文[检索词：首标记与尾标记](https://postext.dev/zh/docs/configuration-headers-footers.md#检索词首标记与尾标记)。

#### 全书页数

`{bookTotalPages}`输出整本书的页数，也就是读者在“第12页，共348页”里看到的那个数。它和`{totalPages}`一样统计实际页数，包括空白页，但覆盖所有章：

- **单独排版的文档**（不带`continuation`的`buildDocument`）就是整本书：`{bookTotalPages}`等于`{totalPages}`。
- **`buildBundle`**先排整本书，把所有章的页数加起来，再用这个总数重新排一遍，所以每一章输出的数字都相同。这个数从不改变分页位置，所以多排一轮就能定下来；不输出`{bookTotalPages}`的配置不会多花任何代价。
- **沙盒**在所有章的页数都已知之后，把总数交给每一章。在此之前，一章输出的是到它自己结尾为止的页数。PDF标签页的整书导出统计它排出的页数：如果某一章因为当时页数尚未确定而输出了别的数字，它会用各章最终合计的页数把书再排一遍。
- **自行逐章排版的宿主程序**把总数作为`continuation.bookPageCount`传入（第一章也要传）。不传时，`{bookTotalPages}`统计到文档结尾为止的页数（`continuation.pageIndexOffset`加上自身的页数），这只对最后一章是正确的。

```ts
footer: {
  elements: [{
    kind: 'text', id: 'folio', content: '{pageNumber} / {bookTotalPages}',
    fontSize: { value: 8, unit: 'pt' },
    placement: { anchor: { to: 'container', edge: 'top' }, size: { width: 'auto', height: 'auto' } },
  }],
}
```

`configUsesPlaceholder(config, 'bookTotalPages')`告诉宿主程序是否值得计算这个总数。

#### 检索词：首标记与尾标记

词典在书眉里印出每页的第一个和最后一个词目（“Aback – Anchor”）；参考书印出第一个和最后一个小节。`{firstMark.<key>}`和`{lastMark.<key>}`用来输出它们。键名指定用什么来标记页面：

- **`h1`到`h6`**：该级的标题。标记是标题的文本，不含编号。
- **段落样式id**（`entry`）：`:::paragraphs{style="entry"}`容器中的段落。标记是段落开头的粗体部分，即词目，去掉末尾的标点：`**Aback.** Said of…`的标记是`Aback`。不以粗体文本开头的段落不产生标记。

`{firstMark.<key>}`是在本页开始的第一个标记，`{lastMark.<key>}`是最后一个。没有任何标记在其上开始的页（一个很长的词条接排过来），两者都输出当时生效的标记，即它之前的最后一个。第一个标记之前的页不输出任何内容；在逐章排版的书中，这指的是该章的第一个标记，因为标记不会从一章带到下一章。跨页拆开的标题或段落只标记它开始的那一页。键名写在点号之后，由字母、数字、`_`和`-`组成，以字母或`_`开头；未知的键名不输出任何内容。

```md
:::paragraphs{style="entry"}
**Aback.** Said of the sails when pressed back against the mast.

**Abaft.** Towards the stern, or behind a given point.
:::
```

```ts
header: {
  elements: [{
    kind: 'text', id: 'guide', content: '{firstMark.entry} – {lastMark.entry}',
    fontSize: { value: 8, unit: 'pt' },
    placement: { anchor: { to: 'container', edge: 'bottom' }, size: { width: 'auto', height: 'auto' } },
  }],
}
```

检索词属于书眉：它们在页眉和页脚槽位中解析（包括标题样式的`header`和`footer`），在标题、篇和目录的设计中不输出任何内容；在标题和篇的设计中，检查面板会把它们标为未知占位符。要在左页显示第一个词目、右页显示最后一个，就用两个元素，分别设`parity: 'even'`和`parity: 'odd'`。标题样式设了`runningChapter: false`的H1不产生`h1`标记。

#### 页面顶部所属的章

`{chapterTitle}`和`{chapterNumber}`指向本页或之前最后开始的一章。在各章接排、章与章之间不分页的书中，如果一页结束了一章，又在靠近页脚处开始下一章，这一页就会在仍属于旧章的文本上方印出新章的标题。`{chapterTitleAtTop}`和`{chapterNumberAtTop}`改为指向页面顶部所属的章，章节接排的小说和许多参考书都是这样做的：

- 第一个块是某章H1的页，指向该章；
- 其他页指向从上一页接排过来的章，即使有新章在页面下方开始；
- 为奇偶补的空白页归属于它后面的页，`always-*`模式的分隔页归属于它前面的页（见[空白页的归属](https://postext.dev/zh/docs/configuration-headings.md#空白页的归属)）；如果奇偶补页后面那一页以一章的结尾开头，而不是以它的H1开头，这张空白页也归属于那一章；
- 带`runningChapter: false`的H1会被跳过。

```ts
header: {
  elements: [{
    kind: 'text', id: 'chapter', content: '{chapterTitleAtTop}', parity: 'odd', pages: 'body',
    fontSize: { value: 8, unit: 'pt' },
    placement: { anchor: { to: 'container', edge: 'bottom-right' }, size: { width: 'auto', height: 'auto' } },
  }],
}
```

和检索词一样，这两个占位符都属于书眉：它们在页眉和页脚槽位中解析，在标题、篇和目录的设计中不输出任何内容。`{attr.<key>}`始终读取最后开始的一章。

#### 由锚点边隐含的对齐方式

当文本元素的`placement.anchor.to`通过`#id`引用另一个元素时，锚点边会为折行后的各行隐含一个默认的文本对齐方式：

- `right-of`和`align-left`隐含文本`align: 'left'`：折行从锚点向右排。
- `left-of`和`align-right`隐含`align: 'right'`：折行贴向离锚定目标最近的一侧。

沙盒的标题编辑器在你更改锚点边或目标时会自动应用这些隐含的对齐方式。它们让折成多行的文本在视觉上始终锚定在相关的元素上（例如折行后“Postext”的“P”与“Introduction”的“I”上下对齐）。

#### 行内标记与描边

文本元素默认用一种字体排出全部文本：`**`、`^`及其他Markdown标记按原样输出。设`inlineMarks: true`后，解析后的文本会被当作行内Markdown读取，支持与正文相同的标记（见**文档格式 → 行内格式**）：

- `**bold**`设为字重700（元素自身的`fontWeight`更重时取后者）；`*italic*`翻转元素的倾斜状态，所以斜体元素中的强调会变成正体；`***both***`两者兼有。下划线形式（`__bold__`、`_italic_`）也可以用。
- `^superscript^`和`~subscript~`以58%的字号排出，上标升高字号的三分之一，下标降低字号的0.15；紧挨在一起的下标和上标（`T~0~^2^`）会上下叠排，与正文相同。
- 反斜杠让标记字符按字面输出（`\*`、`\_`、`\^`、`\~`）。链接保留其文本；代码的反引号会被去掉。

标记在占位符填入之后读取，所以值本身可以带标记：标题属性中的作者行可以把单位编号排成上标。折行、两端对齐、省略号模式、`dropCap`和`paragraphIndent`都适用于带标记的文本；每一段文字都保持元素的颜色。

```json
{ "kind": "text", "id": "authors", "content": "{attr.authors}", "inlineMarks": true, "overflow": "wrap",
  "fontSize": { "value": 11, "unit": "pt" },
  "placement": { "anchor": { "to": "#title", "edge": "below" }, "offset": { "y": { "value": 6, "unit": "pt" } } } }
```

```md
# Snow cover and river flow {authors="Ana Ruiz^1^, Luis Gil^2^ and Marta Sanz^1,3^"}
```

`stroke`围绕字母绘制描边：`width`是线宽，以字形边缘为中心（一半落在字母内侧，一半在外侧；测得的文本宽度不变），`color`默认取文本颜色，`hollow: true`让字母不填充，只显示描边，适合空心的展示数字，或需要从照片上突显出来的标题。描边画在填充之上，在Canvas、HTML（`-webkit-text-stroke`）和PDF（文本渲染模式2，空心时为1）中的做法相同。

```json
{ "kind": "text", "id": "year", "content": "1863", "fontFamily": "Bitter", "fontSize": { "value": 120, "unit": "pt" }, "fontWeight": 700,
  "color": { "hex": "#1d3557", "model": "hex" },
  "stroke": { "width": { "value": 1.5, "unit": "pt" }, "hollow": true },
  "placement": { "anchor": { "to": "page", "edge": "bottom-right" }, "offset": { "x": { "value": -15, "unit": "mm" }, "y": { "value": -20, "unit": "mm" } } } }
```

在PDF中，粗体和斜体部分会嵌入元素字体族中对应的字面，所以字体提供程序必须提供这些字面。

#### 文本默认值与锚定陷阱

你自己写的文本元素从以下取值开始，其中有些会出乎意料：

- **`overflow`取决于所在位置。** 在标题版式或篇章页中，长标题会折成多行；在书眉、页码或目录的篇行中，对所在空间来说太宽的文本会被截成一行并加上`…`。可能较长的书眉（地址、署名）要设`overflow: 'wrap'`，并查看被截断文字的`designTextTruncated`警告。内容中的换行（换行符，或模板、属性值中的`\n`）在所有模式下都会另起一行；省略号模式各自截断每一行。
- **`align`为`'center'`，`verticalAlign`为`'middle'`。** 自动宽度的元素收缩到最长的一行，所以各行彼此居中；要排成齐左的一块，设`align: 'left'`（锚定到另一个元素的自动宽度元素会自行向锚点一侧对齐各行，见上文）。
- **字体为EB Garamond 8 pt、黑色、`lineHeight` 1.2**，与正文用什么字体无关。与配置中的其他行距不同，设计文本的`lineHeight`通常写成一个简单的倍数（`1.2`）；`Dimension`也可以（见上文）。

没有`placement.size.width`（或为`'auto'`）的元素按文本确定自身大小，但只能在锚点与它延伸方向上的容器边缘之间的空间内伸展；对`top`或`bottom`锚点，这个空间是到较近边缘距离的两倍。`offset`也计算在内。背离那条边的偏移不占空间：锚定在`top-left`、`x`为负值（悬挂到左页边距中）的书眉不损失空间，因为它向右延伸。朝向那条边的偏移会让空间缩小同样的量（对`top`或`bottom`锚点缩小两倍），而把锚点推过边缘的偏移则让空间归零：`x`小于容器宽度负值的`top-right`锚点，或横向移动超过容器宽度一半的`top`锚点。空间归零时，省略号模式什么也不输出，`'wrap'`则每行只排一个字符。有三种解决办法：

- 给元素一个固定的`size.width`：固定宽度从不受限制；
- 把它锚定到`'page'`或`'bleed'`，让页面（或出血区）框定它的空间；
- 把它锚定到容器的另一侧边缘。

页眉的容器从裁切上边一直延伸到正文，页脚的容器从正文一直延伸到裁切下边：在页眉中，`top-*`锚点从裁切边量起，`bottom-*`锚点从正文量起，页脚中则相反（见上文**容器框**）。页眉或页脚从不移动正文，并且画在正文之上，所以被推进正文区域的元素会盖住文本。相比之下，章首页的色带画在正文之下；它在文本流中占多少空间见[预留高度](https://postext.dev/zh/docs/configuration-headings.md#保留高度)。

### 竖排文本元素

设了`writingMode: 'vertical-rl'`的文本元素在文本为横排的槽位中竖排：任何书的书眉和页码（它们始终在书页上）以及横排页面的所有设计都是如此。它的排法是：在自身的框里按横排文本排好（这个框顺时针转了四分之一圈），再转回到页面上：

- 它的方框留在定位所给的位置。方框的高度就是一行的长度：由`size.height`设定（或`'auto'`，即文本的长度；`'fill'`，一直延伸到容器边缘），`size.width`决定横向能排几行，`size.maxWidth`限制一行的最大长度。
- `align`沿方框方向放置各行（`'left'`在顶部），`verticalAlign`在横向放置（`'top'`在右侧，即第一行所在的位置），方框的内边距留在它所写明的那一侧。
- 字符的测量和绘制与竖排页面相同：汉字直立，每字占一个全角，标点用竖排字形，拉丁词侧转，短数字排在一格内（`cjk.uprightDigits`）。Canvas、PDF和HTML把它放在同一个矩形中。
- 设`inlineMarks: true`时，方向标记像在正文中一样把一段文字单独处理：`第:tcy[3.0]回`把3.0排在一格内，`:upright[GDP]`把字母逐个直立上下排列，`:sideways[…]`把一段文字侧转；这些片段内部从不断行。横排元素忽略这些标记。
- 竖排元素不排首字下沉。
- 在竖排页面的文本流中（章首页、篇页、方框标题），文本本来就是竖排的，`writingMode`在那里不起作用。

竖排中文书把书眉和页码放在以下三种位置之一（[clreq §7.2](https://www.w3.org/TR/clreq/#x7-2-page-headers-footers-etc)；日文见[JLREQ §2.6](https://www.w3.org/TR/jlreq/#running_heads_and_page_numbers)）：

| 惯例 | 位置 | 设置方法 |
| --- | --- | --- |
| 横排页眉和页脚 | 版心上方和下方，与横排书相同；最常见。 | 保持页眉和页脚原样。 |
| 切口（中缝式，台湾称邊峰） | 沿外侧页边距竖排：章名或书名从版心顶端往下约四个字处开始，页码止于版心底端往上约五个字处，用中文数字，字号约为正文的80 %。 | 两个锚定到`'outer'`的竖排元素，见下文。 |
| 外侧下角 | 页码在页面底部的外侧角上（台湾的中式书规范）。 | 在右翻书中，页脚里放一个`'bottom-left'`、设`parity: 'odd'`的横排元素，和一个`'bottom-right'`、设`parity: 'even'`的横排元素（左翻书则相反）。 |

下面是沙盒添加的切口书眉（**页眉 › 切口书眉（竖排）**），这里按10 pt正文设置（沙盒把它们设为正文字号的80 %）：

```json
{
  "page": { "pageNumbering": { "format": "trad-chinese-informal" } },
  "header": { "elements": [
    { "kind": "text", "id": "head", "content": "{chapterTitle}", "writingMode": "vertical-rl",
      "fontSize": { "value": 8, "unit": "pt" }, "overflow": "clip", "align": "left",
      "placement": { "anchor": { "to": "outer", "edge": "top" }, "offset": { "y": { "value": 4, "unit": "em" } } } },
    { "kind": "text", "id": "folio", "content": "{pageNumber}", "writingMode": "vertical-rl",
      "fontSize": { "value": 8, "unit": "pt" }, "overflow": "clip", "align": "left",
      "placement": { "anchor": { "to": "outer", "edge": "bottom" }, "offset": { "y": { "value": -5, "unit": "em" } } } }
  ] }
}
```

`anchor.to: 'outer'`（见[元素定位](https://postext.dev/zh/docs/configuration-headers-footers.md#元素定位)）是每一页的外侧页边距，所以在右翻书（`page.binding`）中，这两个元素沿右页的左边缘和左页的右边缘竖排。`{pageNumber}`按页码格式输出：`trad-chinese-informal`在第103页给出一百零三，`cjk-decimal`给出一〇三。各槽位的规则照样适用：`pages: 'body'`让书眉不出现在章首页上。书眉和页码之间的短装饰（鱼尾︻、一条线）是锚定到同一框的普通元素。

在VDT中，竖排块带有`vertical`（`VDTDesignTextBlock.vertical`：区域、直立数字和每个字体族的中轴）；它的各行位于块自身旋转后的框中，`xOffset`从方框顶部向下量，`baselineY`从方框右边缘向左量。带标记的行中的一段文字带有`tcy`或`orientation`，与正文的片段相同。

### 线条元素

线条元素渲染一条线：横贯槽位，或纵贯槽位。

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `kind` | `'rule'` | — | 类型判别字段。 |
| `id` | `string` | — | 稳定的id，在槽位内唯一，供`anchor.to: '#id'`引用。 |
| `direction` | `'horizontal' \| 'vertical'` | `'horizontal'` | 横线沿`placement.size.width`延伸（`'fill'` = 到容器边缘），高度为`thickness`。竖线沿`placement.size.height`延伸（`'fill'`或未设置 = 到容器边缘），宽度为`thickness`，例如书眉与页码之间的分隔线。 |
| `color` | `ColorValue` | `#000000` | 线条颜色。 |
| `thickness` | `Dimension` | `0.5 pt` | 线条粗细。省略时按默认值绘制（postext 1.4及更早版本中什么也不画）。 |
| `width` | `Dimension \| 'full'` | `'full'` | `'full'`横跨内容区；Dimension把线条限制为固定长度，位置由`align`决定。 |
| `align` | `'left' \| 'center' \| 'right'` | `'center'` | `width`不为`'full'`时的对齐方式。 |
| `marginFromBody` | `Dimension` | `6 pt` | 线条朝向正文的边与正文边缘之间的绝对距离。与其他元素无关。 |
| `marginFromEdge` | `Dimension` | `0 pt` | 距所对齐的内容边缘的水平缩进。只在`width`为固定`Dimension`且`align`为`'left'`或`'right'`时生效。 |
| `parity` | `'all' \| 'odd' \| 'even'` | `'all'` | 线条出现在哪些页上。 |
| `pages` | `'all' \| 'body' \| 'opener' \| 'part' \| 'blank'` | `'all'` | 线条出现在哪些页面角色上（见文本元素的`pages`字段）。 |
| `reserve` | `boolean` | `true` | 仅用于标题设计：该线条是否计入标题在文本流中预留的高度（见[预留高度](https://postext.dev/zh/docs/configuration-headings.md#保留高度)）。 |
| `placement` | `ElementPlacement` | 由`align` + `marginFromBody` + `marginFromEdge`推导 | 高级定位（见[元素定位](https://postext.dev/zh/docs/configuration-headers-footers.md#元素定位)）。`size.width` / `size.height`设定线条长度；`width: 'fill'`即旧版的`'full'`。 |

### 方框元素

方框元素在槽位内绘制一个圆角矩形，可用作章首页、侧栏或页脚中文本的背景。方框元素只通过`placement`字段定位，没有旧版的平铺简写。填充、描边和圆角半径放在嵌套的`style`对象（`ElementBoxStyle`）中，如“元素定位”下的JSON示例所示。

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `kind` | `'box'` | — | 类型判别字段。 |
| `id` | `string` | — | 稳定的id，在槽位内唯一。同级元素通过`anchor.to: '#id'`锚定到它。沙盒在创建元素时会自动分配一个。 |
| `style.backgroundColor` | `ColorValue` | `transparent` | 填充颜色。设为`transparent`得到只有轮廓的方框。 |
| `style.borderColor` | `ColorValue` | `transparent` | 描边颜色。 |
| `style.borderWidth` | `Dimension` | `0 pt` | 描边宽度。描边画在方框外接矩形的内侧，所以外部尺寸保持不变：描边的外缘沿方框边缘走，圆角方框保持其外圆角半径。与方框一样宽的描边会把方框填满。Canvas、HTML和PDF的画法一致（postext 1.4及更早版本中，Canvas和PDF把描边以边缘为中心绘制，有一半落在方框外）。 |
| `style.borderRadius` | `Dimension` | `0 pt` | 圆角半径。渲染时限制为较短边的一半。 |
| `placement` | `ElementPlacement` | — | 必填。见下文“元素定位”。 |
| `parity` | `'all' \| 'odd' \| 'even'` | `'all'` | 方框出现在哪些页上。 |
| `pages` | `'all' \| 'body' \| 'opener' \| 'part' \| 'blank'` | `'all'` | 方框出现在哪些页面角色上（见文本元素的`pages`字段）。 |
| `reserve` | `boolean` | `true` | 仅用于标题设计：该方框是否计入标题在文本流中预留的高度（见[预留高度](https://postext.dev/zh/docs/configuration-headings.md#保留高度)）。 |

### 图像元素

`image`元素绘制文档中的一个位图或SVG资源，例如扉页上的出版社标志，或书眉中的一个标记。它的大小由`placement.size`决定：`width` / `height`中有一边保留为`'auto'`（默认值）时，另一边按图像的宽高比确定；两边都设定时，图像在方框内等比缩放并居中。缺失的资源或非图像资源不绘制任何内容。

```ts
{
  kind: 'image', id: 'logo', resourceId: 'logo-publisher',
  placement: { anchor: { to: 'page', edge: 'top-left' }, offset: { x: { value: 64, unit: 'mm' }, y: { value: 233, unit: 'mm' } }, size: { width: { value: 83, unit: 'mm' }, height: 'auto' } },
}
```

`resourceId`接受文本元素`content`所接受的占位符，所以同一个设计可以为每个标题绘制不同的图片。在标题样式中设`resourceId: '{attr.vignette}'`后，`# Chapter I {style="opener" vignette="log"}`绘制资源`log`，`# Chapter II {style="opener" vignette="wig"}`绘制`wig`：各章共用同一个样式，不必每张图片克隆一个。页眉或页脚读取本页所属章的属性，与书眉中的`{attr.<key>}`相同；其他占位符同样可用（`'map-{chapterNumber}'`）。结果为空的id，例如没有该属性的标题，不绘制任何内容。自postext 1.8起提供。

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `id` | `string` | — | 稳定的标识符；其他元素可以通过`#id`锚定到它。 |
| `resourceId` | `string` | — | 文档中某个位图或SVG `Resource`的id。可以包含占位符，其中包括`{attr.<key>}`，按每个标题、篇或页面填入。 |
| `decorative` | `boolean` | `false` | 图片只起装饰作用（花饰、色带）：即使它的资源带有替代文本，也不向输出提供替代文本（见下文）。 |
| `placement` | `ElementPlacement` | — | 锚点、偏移和尺寸（见[元素定位](https://postext.dev/zh/docs/configuration-headers-footers.md#元素定位)）。设为`'fill'`的一边延伸到容器边缘。 |
| `parity`、`pages` | 同上 | `'all'` | 图像出现在哪些页上。 |
| `reserve` | `boolean` | `true` | 仅用于标题设计：该图像是否计入标题在文本流中预留的高度（见[预留高度](https://postext.dev/zh/docs/configuration-headings.md#保留高度)）。 |

PDF后端像嵌入图一样嵌入该资源（带印刷母版的SVG会使用母版）；HTML查看器通过`resourceImageUrl`解析它。

设计所绘制的图片，在其资源对它有描述时属于内容：资源的`altText`，没有时取其题注的纯文本（行内标签按其标签文字读，`:ref`有`text`时按`text`读），会写入VDT（`VDTDesignImageBlock.altText`），在HTML中成为其`<img>`的`alt`，在带标签的PDF中成为带`/Alt`的`Figure`，紧接在所属设计的文本之后读出（章的插图页紧接在该章标题之后）。资源两者都没有的图片，以及标为`decorative`的图片，属于装饰：HTML中为`alt=""`加`role="presentation"`，PDF中为artifact。书眉或页脚中的图片每页重复出现，所以无论资源怎么描述都属于版面附属物：VDT中没有`altText`，HTML中为`alt=""`加`role="presentation"`，PDF中为页面的artifact。

### 元素定位

`ElementPlacement`是统一的定位模型，任何设计槽位（页眉、页脚或标题级的高级设计槽位）中的每种元素类型（文本、线条、方框）都使用它。一个定位由三部分状态描述：

```ts
interface ElementPlacement {
  /** 该元素锚定到什么，以及锚定到目标的哪条边。 */
  anchor: {
    to: 'container' | 'page' | 'bleed' | 'outer' | `#${string}`; // container = 槽位；page = 裁切框；bleed = 裁切框 + 出血；outer = 外侧页边距（页眉、页脚）；#id = 另一个元素
    edge: AnchorEdge;
  };
  /** 距锚点的距离。 */
  offset?: { x?: Dimension; y?: Dimension };
  /** 可选的固定宽度 / 高度。宽度还接受 'fill'（横跨槽位）。
   *  `maxWidth` 限制 'auto' 宽度（文本）的上限：元素仍收缩贴合其内容，
   *  所以锚定到它的元素保持相连，但长文本会在此处折行或加省略号，
   *  这样书眉可以为挂在它旁边的标签预留空间，而不会把标签挤掉。 */
  size?: { width?: Dimension | 'fill' | 'auto'; height?: Dimension | 'fill' | 'auto'; maxWidth?: Dimension };
}
```

`AnchorEdge`接受：

- **容器边**（`anchor.to`为`'container'`、`'page'`或`'bleed'`时）：`top`、`top-left`、`top-right`、`bottom`、`bottom-left`、`bottom-right`、`left`、`right`。
- **相对元素的边**（`anchor.to === '#someId'`时）：`right-of`、`left-of`、`below`、`above`、`align-top`、`align-bottom`、`align-left`、`align-right`。

每种相对元素的边都把本元素的一个角放在所锚定元素的一个角上，再由`offset`从那里移动：

- `right-of`：本元素左上角放在目标右上角（在目标旁边，顶部齐平）；`left-of`：本元素右上角放在目标左上角；
- `below`：本元素左上角放在目标左下角（在目标下方，左边齐平）；`above`：本元素左下角放在目标左上角；
- `align-top`和`align-left`：本元素左上角放在目标左上角。这两个名字给出相同的定位：顶边和左边都对齐；
- `align-bottom`：本元素左下角放在目标左下角；
- `align-right`：本元素右上角放在目标右上角。

相对元素的边与`'container'`、`'page'`或`'bleed'`一起使用，或容器边与`'#id'`一起使用时，都按左上角处理。

`anchor.to: 'page'`把元素锚定到**裁切框**（裁切后的实际页面），`'bleed'`则锚定到四边各扩出`cutLines.bleed`的裁切框（关闭裁切线时与裁切框相同）。这两个框也成为`size: 'fill'`和自动宽度限制的参照，所以色带可以不受页边距影响，从一边延伸到另一边：

```json
{ "kind": "box", "id": "band", "placement": { "anchor": { "to": "bleed", "edge": "top-left" }, "size": { "width": "fill", "height": { "value": 6, "unit": "cm" } } }, "style": { "backgroundColor": { "hex": "#1d3557", "model": "hex" } } }
```

开启裁切线时，元素画出出血框之外的部分都会被裁掉（见[裁切线](https://postext.dev/zh/docs/configuration-page-layout.md#裁切线)）。

`anchor.to: 'outer'`（页眉和页脚槽位）把元素锚定到页面的**外侧页边距**：横向从版心边缘到远离书脊一侧的裁切边，纵向从版心顶端到底端。在左翻书中，它位于右页的右侧和左页的左侧，右翻书则相反（`page.binding`），所以一个元素就能同时服务跨页的两页：例如沿切口竖排的书眉（见[竖排文本元素](https://postext.dev/zh/docs/configuration-headers-footers.md#竖排文本元素)）。在其他槽位中，它按`'container'`处理。文本元素的`offset`可以用`em`表示，即它自身`fontSize`的em：版心顶端往下四个字就是`{ "y": { "value": 4, "unit": "em" } }`。

在标题的高级设计槽位中，锚定到页面和出血区的元素不会增加为标题预留的高度，除非它们延伸到标题顶边以下（横跨页面顶部的色带衬在章首页后面；延伸到标题以下的色带会把正文往下推）。用`advancedDesign.minHeight`可以无论如何都预留一个固定的章首页高度，对不应推动文本的元素则设`reserve: false`。完整规则见[预留高度](https://postext.dev/zh/docs/configuration-headings.md#保留高度)。

每个元素都有一个稳定的`id`（由沙盒自动分配；你也可以手动设置）。锚定到其他元素的元素构成一个小型依赖图，引擎在测量前解析它，所以一个元素可以接在另一个元素后面定位，无须手动指定坐标。

旧版的`align` + `marginFromBody` + `marginFromEdge`结构在输入时解析，并在解析配置时改写为定位，所以已有的配置无须改动即可继续使用。
