穩定性: 實驗性
分頁媒體 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 支援矩陣;此處不主張任何端到端一致性。未重現任何規範文字。