稳定性: 实验性
分页媒体 CSS 预览标志(GCPM 运行内容、命名页面、页面浮动)
可选启用的预览。 这四项 CSS 特性默认关闭。当标志关闭时,引擎会产出与从不知道该特性存在的构建字节完全一致的输出。只在你确实需要时才开启某项特性,并针对你的文档验证结果。
HTML 渲染器从 CSS Paged Media 与 Generated Content for Paged Media(GCPM)模块中新增了四项可选启用的分页媒体特性。每一项都是 CssFeatureFlags 上的一个独立标志。每一项都带有诚实的 fail-closed(失败即关闭)边界:单遍引擎无法忠实解析的结构,会被丢弃或降级并附带一个具名诊断信息,绝不会渲染错误。
| 特性 | 标志 | 开启时的行为 |
|---|---|---|
| 命名字符串(GCPM) | runningStrings | string-set 捕获,加上 @page 边距框中的 string()——即运行页眉与页脚。 |
| 命名页面(Paged Media L3) | namedPagesAdvanced | @page <ident>、page: 属性,以及 :first / :left / :right / :blank——逐页的边距框与装饰。 |
| 运行元素(GCPM) | runningElements | position: running(<ident>) 加上 content: element(<ident>)——在边距框中重放某个元素的文本。 |
| 页面浮动(Page Floats L3) | pageFloats | float: top | bottom | snap——将一个框移入页面的顶部或底部带区。 |
composer require nextpdf/core:^3这些标志随核心包一起分发。CssFeatureFlags 公开接口是 @since 6.1.0。引擎版本(Version::VERSION)保持不变;这些特性是增量式的,且默认关闭。
概念总览
标题为“概念总览”的章节渲染器是单遍且流式的(参见 ADR-001)。它不保留任何文档树,并按文档顺序一次性写出输出。该约束塑造了这里的每一项特性。每项特性在一次前向遍历中解析它能看到的内容,对任何需要第二遍或保留树的内容则 fail closed(失败即关闭)。该边界是有文档记录的,而非隐藏的——知道一项特性在哪里止步,是使用它的一部分。
你通过构造一个把对应标志设为 true 的 CssFeatureFlags 并将其传给 Config 来启用某项特性。当一个标志关闭时,相应的 CSS 会被解析并忽略,与一个不受支持的属性完全一样,因此输出与不带该特性的构建字节完全一致。
命名字符串——runningStrings
标题为“命名字符串——runningStrings”的章节string-set: <ident> content() 会在引擎经过该元素时记录一个值。@page 边距框内的 string(<ident>) 引用随后会解析为该页上看到的最近一个值。这是用于跟踪当前章或节的运行页眉的标准机制。
解析采用单遍的“本页最后所见”方式。一个 string() 引用会解析为引擎在排布该页边距框之前记录的最后一个值。
Fail-closed 边界。 标志关闭时,string() 解析为空字符串,输出保持字节一致。格式错误的 string-set 内容列表会丢弃那一个赋值对并继续;它绝不会中止渲染。
命名页面——namedPagesAdvanced
标题为“命名页面——namedPagesAdvanced”的章节page: <ident> 属性把一个元素指派到一个命名页面上下文,而一条匹配的 @page <ident> 规则提供该上下文的边距框与页面装饰。页面伪类 :first、:left、:right 与 :blank 分别选择首页、正面与背面页,以及有意留空的页面。
此特性选择的是某个命名或伪页面的边距框与装饰。它不改变页面几何。
Fail-closed 边界。 一条试图改变几何的命名或伪 @page 规则——size、rotate,或一个会调整页面区域尺寸的内容框边距——会以 UnsupportedNamedPageException 进行 fail closed,而不是悄无声息地产出一个错位的页面。伪类匹配通道是第一个切片;更广泛的选择器情形则被推迟并有文档记录。
运行元素——runningElements
标题为“运行元素——runningElements”的章节position: running(<ident>) 把一个元素从正常流中移除并将其停放在一个名称之下。边距框中的 content: element(<ident>) 随后会在每一页上重放该元素。当一个页眉需要某个标题的完整带样式文本、而不仅仅是一个被捕获的字符串时,请使用它。
Fail-closed 边界。 此切片只重放运行元素的文本。富内容——图像、被替换元素、嵌套块结构——会被丢弃,并且引擎会发出一个 HTML_RUNNING_ELEMENT_DEGRADED 诊断,使这一损失可见而非沉默。一个引用自身的 running() 元素、一个嵌套的 running(),或一次超出内部预算的捕获,都会 fail closed。标志关闭时,running() 与 element() 处于惰性状态。
页面浮动——pageFloats
标题为“页面浮动——pageFloats”的章节float: top、float: bottom 与 float: snap 会沿块轴把一个框移入页面的顶部或底部带区,并预留该带区的高度,使周围文本绕开被预留的区域重新排布。
float: bottom(以及解析到底部带区的 snap)是单遍引擎可直接处理的情形:该框会被捕获,并在页面关闭时放入页面的底部带区。float: top 退化为页面顶部带区。
Fail-closed 边界。 沿行内轴的 snap(snap-inline)不受支持。一个带有不可移动副作用的框——例如一个链接注释,其矩形被绑定到它在流中的位置——无法被安全地重新定位,因此它会回退到正常流,并且引擎会发出一个解释该回退的 HTML_PAGE_FLOAT_* 诊断。标志关闭时,float: top | bottom | snap 被当作一个不受支持的值并忽略。
API 接口
标题为“API 接口”的章节| 符号 | 位置 | 角色 |
|---|---|---|
CssFeatureFlags | src/Html/CssFeatureFlags.php | 不可变的可选启用标志集;构造器接受 runningStrings、namedPagesAdvanced、runningElements、pageFloats(全部默认 false)。 |
Config::withCssFeatureFlags(CssFeatureFlags $flags): self | src/Core/Config.php | 把标志集附加到一份文档配置上。 |
CssFeatureFlags::forMode(CssRenderingMode $mode, ?self $explicit = null): self | src/Html/CssFeatureFlags.php | 为某个渲染模式解析出一个标志集(Safe 模式会强制每个标志关闭;Normal 模式使用显式提供的标志集,未提供时使用 allEnabled())。 |
UnsupportedNamedPageException | src/Html/PagedMedia/UnsupportedNamedPageException.php | 当一条命名/伪 @page 规则改变页面几何时抛出。 |
诊断警告码通过渲染结果的告知通道暴露:HTML_RUNNING_ELEMENT_DEGRADED、HTML_RUNNING_ELEMENT_* 家族,以及 HTML_PAGE_FLOAT_* 家族。
代码范例——快速上手
标题为“代码范例——快速上手”的章节为一个跟踪当前章的运行页眉启用命名字符串。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;use NextPDF\Core\Document;use NextPDF\Html\Css\CssFeatureFlags;
$config = (new Config())->withCssFeatureFlags( new CssFeatureFlags(runningStrings: true),);
$doc = Document::createStandalone($config);$doc->addPage();$doc->writeHtml( '<style>' . 'h2 { string-set: chapter content(); }' . '@page { @top-center { content: string(chapter); } }' . '</style>' . '<h2>Introduction</h2><p>Body text…</p>',);$doc->save(__DIR__ . '/running-header.pdf');代码范例——正式环境
标题为“代码范例——正式环境”的章节同时启用多个标志,并把告知通道当作某个结构发生降级的信号来对待。这些标志彼此独立;只开启你用到的那些。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;use NextPDF\Core\Document;use NextPDF\Exception\UnsupportedNamedPageException;use NextPDF\Html\Css\CssFeatureFlags;
$config = (new Config())->withCssFeatureFlags(new CssFeatureFlags( runningStrings: true, namedPagesAdvanced: true, runningElements: true, pageFloats: true,));
$doc = Document::createStandalone($config);$doc->addPage();
try { $doc->writeHtml($html);} catch (UnsupportedNamedPageException $e) { // A named @page rule tried to change page geometry (size/rotate/margin). // The engine fails closed rather than emit a misaligned page. throw $e;}
$doc->save($out);
// Inspect $doc's advisory channel for HTML_RUNNING_ELEMENT_DEGRADED and// HTML_PAGE_FLOAT_* before treating the output as final.边界情况与陷阱
标题为“边界情况与陷阱”的章节- 四个标志彼此独立且默认关闭。 一个关闭的标志会产出字节一致的输出。只启用你用到的。
- 当
runningStrings关闭时,string()为空,这是按设计如此。关闭这一情形没有警告;它是有文档记录的默认行为。 - 运行元素只重放文本。 运行元素内部的图像与嵌套块会随
HTML_RUNNING_ELEMENT_DEGRADED被丢弃。请检查告知通道。 - 命名页面不能改变几何。 一条改变几何的命名/伪
@page规则会抛出UnsupportedNamedPageException。请通过Config设置页面尺寸与旋转,而非通过命名@page规则。 - 页面浮动会让链接保留在流中。 一个包含链接注释的浮动框会回退到正常流并带有一个
HTML_PAGE_FLOAT_*诊断,因为链接矩形被绑定到它在流中的位置。
每项特性都只增加有限的单遍工作量:命名字符串为每个 string-set 元素记录一个值;命名页面增加一次逐页边距框解析;运行元素为每个被停放的元素捕获一个文本缓冲;页面浮动为每页预留一个带区。没有任何一项会保留文档树,因此流式渲染器的 O(嵌套深度) 内存模型得以保持。逐页的 performance_budget(wall_ms: 1500、peak_mb: 64)保持不变。
安全性注意事项
标题为“安全性注意事项”的章节这些标志不会扩大输入面。HTML 安全策略、CSS 属性允许清单,以及样式表字节与嵌套上限均原样适用。被捕获的字符串与元素内容会经过与任何其他文本相同的输出路径进行转义。这些特性增加的是布局行为,而非一条新的摄取通道。
符合性
标题为“符合性”的章节| 主张 | 标准 | 条款 |
|---|---|---|
string-set 记录一个命名字符串;string() 在页面边距框中解析它。 | W3C CSS Generated Content for Paged Media | §3 |
position: running() 把一个元素从流中移除;content: element() 重放它。 | W3C CSS Generated Content for Paged Media | §5 |
page 属性与 @page <ident> 选择一个命名页面上下文。 | W3C CSS Paged Media Module Level 3 | §3 |
float: top | bottom | snap 沿块轴把一个框浮动到一个页面带区。 | W3C CSS Page Floats Level 3 | §5 |
这些是工作组模块特性的预览实现。NextPDF 实现的是一个单遍子集,并带有上述有文档记录的 fail-closed 边界。逐属性的已验证状态记录在 CSS 支持矩阵中;此处不主张任何端到端符合性。未重制任何标准原文。