引言
分页媒体在文档内容的展示上有许多特殊需求,这些需求是在印刷书籍的悠久历史中逐渐发展而来的。活页眉和活页脚有助于导航。注释可以作为脚注出现在页面底部。页面本身的属性也可能会根据其内容或在文档中的位置发生变化。引导符用于在视觉上连接相关内容。交叉引用可能需要生成文本。一些分页媒体格式(如 PDF)使用书签进行导航。
本模块定义了新的属性和值,使作者能够将这些技术应用于分页媒体。
值定义
本规范遵循CSS 属性定义惯例(参见[CSS21]),并使用值定义语法(参见[CSS-VALUES-3])。 未在本规范中定义的值类型在 CSS Values & Units [CSS-VALUES-3] 中定义。 与其他 CSS 模块的结合可能会扩展这些值类型的定义。
除了各自定义中列出的特定属性值之外, 本规范中定义的所有属性 也接受CSS 全局关键字作为其属性值。 为了可读性,这些并未在每处重复列出。
1. 活页眉和活页脚
[CSS3PAGE] 描述了可用于活页眉和活页脚的十六个页面边距盒,但并未描述在这些盒中插入内容的机制。本模块提供了两种实现方法。命名字符串可将文本复制以便在边距盒中复用。活动元素可将元素(包含样式和结构)从文档移动到边距盒。1.1. 命名字符串
string-set 属性将元素的文本内容复制到一个命名字符串,其功能类似于变量。命名字符串的文本内容可通过string()函数获取。由于这些变量在某一页上可能会发生变化,string()函数的第二个可选参数允许作者选择页面上的哪个值被使用。1.1.1. string-set 属性
| Name: | string-set |
|---|---|
| Value: | [ <custom-ident> <content-list> ]# | none |
| Initial: | none |
| Applies to: | 所有元素,但不包括伪元素 |
| Inherited: | no |
| Percentages: | N/A |
| Computed value: | 指定值 |
| Canonical order: | 按语法顺序 |
| Animation type: | 离散 |
用户代理应在所有媒体上支持该属性,包括非可视媒体。
string-set 属性包含一个或多个对,每对由自定义标识符(命名字符串的名称)后跟一个<content-list>组成,用于描述如何构造命名字符串的值。
<content-list> 可扩展为以下值之一或多个,顺序不限。
<content-list> = [ <string> | <counter()> | <counters()> | <content()> | <attr()> ]+
- <string>
- 一个字符串,定义见[CSS21]
- <counter()>
- 一个counter()函数,详见[CSS21]。
- <counters()>
- 一个counters()函数,详见[CSS21]。
- <content()>
- 下文描述的content()函数。
- <attr()>
- 一个attr()函数,定义见[CSS-VALUES-3]
1.1.1.1. content() 函数
content() = content([text | before | after | first-letter ])
- text
- 元素的字符串值,效果等同于设置
white-space: normal。这是默认值。 - before
::before伪元素的字符串值,效果等同于设置white-space: normal。- after
::after伪元素的字符串值,效果等同于设置white-space: normal。- first-letter
- 元素的首字母,定义见
::first-letter伪元素
命名字符串的内容值在元素内容盒首次创建时(或如果元素的 display 为 none 时,假定会创建时)被分配。页面的入口值为上一页结束时生效的赋值,出口值为当前页结束时生效的赋值。
每当元素的值发生变化时,命名字符串的值也会被更新。用户代理必须能够记住命名字符串的多个值,因为string()函数可以返回过去、现在或未来的赋值值。
HTML:
<h1>Loomings</h1>
CSS:
h1::before { content: 'Chapter ' counter(chapter); }
h1 { string-set: header content(before) ':' content(text); }
h1::after { content: '.'; }
命名字符串“header”的值将为“Chapter 1: Loomings”。
<section title="Loomings">
CSS:
section { string-set: header attr(title) }
“header”字符串的值将为“Loomings”。
1.1.2. string() 函数
string() 函数用于通过content属性将命名字符串的值复制到文档中。该函数需要一个参数,即命名字符串的名称。由于命名字符串的值在页面上可能会多次变化(因为定义该字符串的元素实例不断出现),可选的第二个参数用来指定应使用命名字符串的哪个值。string()函数的第二个参数为以下关键字之一:
- first
- 使用页面上的第一次赋值的值。如果页面上没有赋值,则使用入口值。
first是默认值。 - start
- 如果该元素是页面上的第一个元素,则使用第一次赋值的值。否则使用入口值。如果该元素尚未出现,入口值可能为空。
- last
- 使用该命名字符串的出口值。
- first-except
- 与
first一致,但在赋值所在的页面上使用空字符串。
@page {
size: 15cm 10cm;
margin: 1.5cm;
@top-left {
content: "first: " string(heading, first);
}
@top-center {
content: "start: " string(heading, start);
}
@top-right {
content: "last: " string(heading, last);
}
}
h2 { string-set: heading content() }
下方示意图展示了各页上“heading”字符串的 first、start 和 last 赋值:
1.2. 活动元素
许多页眉和页脚不能仅用未格式化的文本表示。例如,作为活页眉的书名可能包含斜体单词。需要一种机制将元素移动或复制到边距盒中。为此,我们为 position 属性增加了running()值,并为 content 属性增加了element()值。@page {
@top { content: element(header); }
}
h1 { position: running(header); }
在该示例中,h1 元素被放置在 @top 边距盒内,保留格式和所有子元素,并不会在常规文档流内显示。
1.2.1. running() 值
position: running(custom-ident) 会将该元素(及其关联的 ::before 和 ::after 伪元素)从常规文档流移除,并可通过element()放到页面边距盒。该元素保留其在文档中的继承属性,但不会在原文档位置显示。
| Name: | position |
|---|---|
| New values: | <running()> |
running() = running( <custom-ident> )
HTML:
<p class="rh"><i>Miranda v. Arizona</i> in Context</p> <h2><i>Miranda v. Arizona</i> in Context</h2>
CSS:
@top-center {
content: element(heading);
}
p.rh {
position: running(heading);
}
p.rh::before {
content: counter(page) ' / ';
}

element()只能用于页面边距盒,且不能与 content 属性的其他可选值组合使用。
如果我们也能复制(而不仅仅是移动)元素,这个想法会更有用。这将避免上面示例中的 HTML 重复。
Bert Bos 提出了一个替代语法,允许元素被移动或复制到活页眉中。如下例所示,h2 元素既出现在文档正常位置,也会被复制到活页眉。
h2 {
display: block;
running: chapter;
font-size: 18pt;
font-weight: bold;
}
h2:running {
display: inline;
font-size: 11pt;
font-weight: normal;
font-variant: small-caps;
letter-spacing: 1pt;
}
@page {
@top-center {
content: element(chapter);
}
}
| Name: | running |
|---|---|
| Value: | <custom-ident> |
| Initial: | none |
| Applies to: | 元素 |
| Inherited: | no |
| Percentages: | N/A |
| Computed value: | 指定值 |
| Canonical order: | 按语法顺序 |
| Animation type: | 离散 |
用户代理应在所有媒体上支持该属性,包括非可视媒体。
1.2.2. element() 值
content 属性的 element() 值可将一个(通过 running() 移出常规流的)元素放置到页面边距盒中。每当元素的值发生变化时,element() 的值也会更新。
与 string() 类似,element() 也可以带一个可选关键字,用于描述在页面上有多次赋值时应使用哪个值。用户代理必须能够记住多个值,因为 element() 可以返回赋值的过去、当前或未来的值。
| Name: | content |
|---|---|
| New values: | <element()> |
element() = element( <custom-ident> , [ first | start | last | first-except ]? )
2. 脚注
辅助内容可以被移动到页面的底部或侧边。当这样的内容被移动到页面底部并留下一条引用标记时,就创建了脚注。2.1. 术语
脚注是复杂的对象(参见 脚注章节,[dpub-latinreq]),因此在继续之前,定义一些术语会很有帮助。

- footnote element
- 包含脚注内容的元素,将从文档流中移除并作为脚注显示。
- footnote marker (也称为 footnote number)
- 位于脚注正文旁的数字或符号,用于标识特定脚注。脚注标记应与相应脚注调用使用相同的数字或符号,尽管标记可以包含额外的标点符号。
- footnote body
- 脚注标记位于脚注元素前,与脚注元素共同组成脚注正文,最终放置在脚注区域。
- footnote call (也称为 footnote reference)
- 主文本中出现的数字或符号,用于指向脚注正文。
- footnote area
- 用于显示脚注的页面区域。
- footnote rule (也称为 footnote separator)
- 水平分隔线通常用于将脚注区域与页面其他部分分隔开。该分隔线(及整个脚注区域)不能在没有脚注的页面上渲染。
2.2. 创建脚注
通过对元素应用float: footnote,该元素会变成脚注。这将触发以下操作:
- 脚注元素从文档流中移除,其位置插入一个
::footnote-call伪元素,用作对脚注的引用。 - 一个用于标识脚注的
::footnote-marker伪元素被放在脚注元素的开头。它们一起构成脚注正文。 - 脚注计数器递增。
- 脚注正文被放置在页面底部的脚注区域。来自同一页的脚注元素按文档顺序放入该页的脚注区域。
<p>Though the body was erect, the head was thrown back so that the closed eyes were pointed towards the needle of the tell-tale that swung from a beam in the ceiling.<span class="footnote">The cabin-compass is called the tell-tale, because without going to the compass at the helm, the Captain, while below, can inform himself of the course of the ship.</span></p>
CSS:
@page {
@footnote {
float: bottom;
}
}
span.footnote { float: footnote; }
为什么在脚注区域要用 float:bottom?将脚注浮动到脚注区域,然后再将脚注区域自身浮动,看起来过于复杂,因为实现上并不允许脚注区域浮动到其他地方。注意有些实现允许脚注区域绝对定位。
2.3. 脚注类型
以下是 float 属性的新值,用于创建脚注元素:| Name: | float |
|---|---|
| New values: | footnote |
- footnote
- 每个脚注元素被放置在页面的脚注区域中
footnote-display 属性决定脚注是以块级元素还是内联元素显示。
| Name: | footnote-display |
|---|---|
| Value: | block | inline | compact |
| Initial: | block |
| Applies to: | elements |
| Inherited: | no |
| Percentages: | N/A |
| Computed value: | specified value |
| Canonical order: | per grammar |
| Animation type: | discrete |
- block
- 脚注元素以块级元素的方式放入脚注区域
- inline
- 脚注元素以内联元素的方式放入脚注区域
- compact
- 由用户代理决定脚注元素是以块级还是内联方式放置。如果同一行可以容纳两个以上脚注,则应以内联方式放置。
2.4. 脚注区域
可以用于显示脚注的页面区域,在页面上下文中通过@footnote
规则描述。该规则定义了一个盒子,若被使用,将包含该页所有出现的脚注元素。
2.4.1. 脚注区域的位置
脚注区域的底边缘与页面区域的底部贴合。脚注区域只能包含脚注。脚注在多栏文本中如何工作?Prince 使用
float: prince-column-footnote 可在栏底生成脚注而不是页面底部。
支持脚注的实现一般也支持
float: bottom 等页面浮动。页面浮动内容应出现在脚注区域之上,这应如何规范?
2.4.2. 脚注区域的尺寸
脚注区域上的 max-height 属性限制该区域的大小,除非页面只包含脚注(如文档最后一页可能出现的情况)。
由于页面只包含脚注是不理想的,用户代理可以为脚注区域设置默认 max-height 值。
2.5. 脚注计数器
脚注计数器 是与脚注元素关联的预定义计数器。它的值用于标识脚注的数字或符号,在脚注调用和脚注标记中都要使用,并应为每个脚注递增。
2.5.1. 脚注计数器的值
脚注计数器与其他计数器一样,可以采用任意计数器样式。脚注常用符号序列。
::footnote-call { content: counter(footnote, symbols('*', '†', '‡', '§')); }
::footnote-marker { content: counter(footnote, symbols('*', '†', '‡', '§')) '. '; }
2.5.2. 重置脚注计数器
脚注计数器可以在每一页重置。
注意,脚注计数器的值应取决于脚注元素在文档树中的位置,而不是最终放置的位置。有时脚注元素会被放到脚注调用之后的页面,但两者必须使用同一个计数器值。
2.6. footnote-call 伪元素
当脚注元素被移出文档流时,会在其原位置插入一个 ::footnote-call 伪元素。默认情况下,该伪元素的内容为脚注计数器的值,样式为上标数字。
::footnote-call {
content: counter(footnote);
vertical-align: baseline;
font-size: 100%;
line-height: inherit;
font-variant-position: super;
}
2.7. footnote-marker 伪元素
::footnote-marker 伪元素表示脚注元素的标记,即用来标识每个脚注的数字或符号。该伪元素行为类似 ::marker 伪元素(定义见[CSS3LIST])。它被放置在上级父元素内容的开头,默认是内联的。::footnote-marker
可以像其他 ::marker 元素一样设置样式。默认样式应包括 list-style-position: inside。
2.8. 脚注渲染与 footnote policy
渲染脚注有一定复杂性。如果脚注出现在页面底部附近,则页面上可能没有足够空间容纳脚注正文。footnote-policy 属性允许作者对复杂页面的脚注渲染方式进行一定控制。
| Name: | footnote-policy |
|---|---|
| Value: | auto | line | block |
| Initial: | auto |
| Applies to: | elements |
| Inherited: | no |
| Percentages: | N/A |
| Computed value: | specified value |
| Canonical order: | per grammar |
| Animation type: | discrete |
- auto
- 用户代理决定如何渲染脚注,并且可以将脚注正文放在脚注引用之后的页面。脚注正文绝不可出现在引用之前的页面。
- line
- 如果某个脚注正文因空间不足无法放在当前页,用户代理会在包含脚注引用的行前强制分页,使引用和正文都出现在下一页。注意,用户代理在这样做时必须遵循孤行寡行设置,因此可能需要在更前的行插入分页。
- block
- 与 line 类似,但强制分页发生在包含脚注的段落前。
2.9. 未来方向
下一版本将包括边注、分栏脚注和多脚注区。3. 选择页面
分页文档由一系列页面组成。[CSS3PAGE] 定义了 页面选择器,可选择文档首页、左页、右页和空白页。这里我们扩展页面选择器的概念,使其可以选择任意文档页。
3.1. 页面选择器
:nth() 页面伪类可选择任意文档页。该伪类的参数为 An + B,定义见 [CSS3SYN]。应用于默认 @page 规则时,:nth() 选择索引与参数匹配的文档页。:nth() = :nth( <an+b> [of <custom-ident>]? )
:nth() 与页面计数器无关,后者可重置且支持多种编号方案。
当 :nth() 选择器应用于命名页面,且该页面属于页面组(见下文)时,将选择页面组中的第 n 页。
3.2. 页面组
许多分页文档具有重复结构,包括多个章节、节或文章。每个子区块的首页通常需要特殊处理,但 [CSS3PAGE] 并未定义如何选择每章首页(区别于文档首页)。当 page 属性应用于同时拥有强制分页属性的元素时,会创建一个 页面组。页面组 是由该元素的所有实例生成的页面集合。每渲染一个新实例,就会开始新的 页面组。
一个页面可以属于多个页面组,因为某个 页面组 可能有祖先或后代属于另一个 页面组。
div {
page: A;
break-before: page;
}
child {
page: B;
break-before: page;
}
@page :nth(5 of A) /* 选择每个 <div> 的第 5 页 */ @page :nth(1 of B) /* 选择每个 <child> 的第 1 页 */ @page :nth(5) /* 选择文档的第 5 页 */
考虑如下 HTML:
<div class="chapter"> <h1>Chapter One</h1> <p>some text</p> <table class="broadside"> ... </table> ... </div> <div class="chapter"> <h1>Chapter Two</h1> <p>some text</p> ... <table class="broadside"> ... </table> ... </div>
以及 CSS:
div.chapter {
page: body;
break-before: page;
}
table.broadside {
page: broadside;
break-before: page;
}
在此情况下,每个章节将形成独立的页面组。@page:nth(3 of body) 将选择每章的第 3 页,即使该页实际使用的是 “broadside” 命名页。@page:nth(1) 只会选择文档的第 1 页,@page:first 也是如此。
4. 引导符(已迁移)
现在已在 [CSS3-CONTENT] 中描述
5. 交叉引用(已迁移)
现在已在 [CSS3-CONTENT] 中描述
6. 书签(已迁移)
现在已在 [CSS3-CONTENT] 中描述
附录 A:它们现在在哪?
许多曾出现在 2011 年 11 月 29 日工作草案 的章节已被移至其他规范。以下是各部分的迁移说明。
印刷标记与出血区
本节已移至 CSS 分页媒体模块第 3 级。
CMYK 颜色
本节已移至 CSS 颜色模块第 5 级。
空白页样式
本节已移至 CSS 分页媒体模块第 3 级
分页展示
本节已移至 CSS 溢出模块第 4 级。
页面间导航
相关内容见 WHATWG CSS 书籍。
页面浮动
本节已移至 CSS 页面浮动。
选择列和页面
关于选择列的简要说明见 WHATWG CSS 书籍。
附录 B:默认 UA 样式表
本附录为说明性内容,旨在帮助 UA 开发者实现 HTML 的默认样式表,但 UA 开发者可根据需要自由忽略或修改。
@page {
counter-reset: footnote;
@footnote {
counter-increment: footnote;
float: bottom;
column-span: all;
height: auto;
}
}
::footnote-marker {
content: counter(footnote);
list-style-position: inside;
}
::footnote-marker::after {
content: '. ';
}
::footnote-call {
content: counter(footnote);
vertical-align: super;
font-size: 65%;
}
@supports ( font-variant-position: super ) {
::footnote-call {
content: counter(footnote);
vertical-align: baseline;
font-size: 100%;
line-height: inherit;
font-variant-position: super;
}
}
h1 { bookmark-level: 1 }
h2 { bookmark-level: 2 }
h3 { bookmark-level: 3 }
h4 { bookmark-level: 4 }
h5 { bookmark-level: 5 }
h6 { bookmark-level: 6 }
附录 C:变更记录
自 2014 年 5 月 13 日工作草案 后的变更:
- 明确书签只通过 bookmark-level 属性创建。移除了 none 作为 bookmark-label 的值。
- 将交叉引用、引导符和书签章节移至 CSS 生成内容模块。
- 修复了错误的断开值。参见 问题 #3524。
- 该规范有了新的编辑者。
自 2013 年 9 月 24 日编辑草案 后的变更:
- 该规范有了新的编辑者。
- 所有文本和示例都已重写。
- 为 string-set 属性添加了 attr(<identifier>) 值。Prince 和 AntennaHouse 都支持此值。
- 新增 footnote-policy 属性,用于控制复杂情况下脚注的渲染。
- 新增 footnote-display 属性,支持内联脚注。
- 移除了边注章节。
- 移除了页面和列中选择元素的相关章节。
- 移除了 page-group 属性,并为 nth() 页面伪类添加可选参数以支持页面组内选择。
自 2011 年 11 月 29 日工作草案 后的变更:
- 印刷标记与出血章节移至 CSS 分页媒体模块第 3 级
- CMYK 颜色章节移至 CSS 颜色第 5 级。
- 已删除空白页样式章节
- 分页展示章节移至 CSS 溢出模块第 3 级。
- 页面间导航已移至 WHATWG CSS 书籍
- 页面浮动章节移至 CSS 页面浮动
- 已删除首页伪元素章节
- 已删除选择列和页面章节
- 从 string-set 属性中移除了 env() 函数
- 移除了 leaders 的 alignment 值
- 规定 leader 只能占用一行
- target-text 的 content() 值更改为 content(text)
- 从 content 属性中移除了 target-pull() 值
与 WHATWG CSS 书籍 规范的区别:
- 为 string-set 属性添加了 attr(<identifier>) 值。Prince 和 AntennaHouse 都支持此值。
- CSS 书籍 没有 footnote-display 属性。
- CSS 书籍 没有 footnote-policy 属性。
- 进一步明确了
nth()页面伪类与页面组概念的关系,这可能使 page-group 属性变得多余。 - 本规范未将
:first页面伪选择器重定义为选择页面组的第一页。 -
本规范未考虑如下内容:
- 命名区域
- 在页面和列内选择元素
-
range()页面伪类 - 选择列
- 基线节奏
- 扩展盒模型
- 字符替换
- 微排版
隐私注意事项
目前本规范未报告新的隐私注意事项。
安全注意事项
目前本规范未报告新的安全注意事项。
致谢
本工作离不开 Håkon Wium Lie 的巨大贡献。Chris Lilley、Elika J. Etemad、Alan Stearns、L. David Baron、Bert Bos、Florian Rivoal、[$your_name, ", " ]+ 和 Liam Quin 提供了宝贵的反馈意见。