Using CSS string-set for Print Headers
The CSS string-set property allows developers to
dynamically extract text content from elements within a document and
inject that content into margin boxes, such as running headers and
footers, during print rendering. Defined in the CSS Paged Media Module,
string-set pairs with the string() function to
create context-aware headers that update automatically as readers move
through different sections, chapters, or pages of a printed
document.
How string-set Works
In standard web layouts, headers typically remain fixed or scroll
with the viewport. In paged media (such as PDFs or physical prints),
headers reside in page margin boxes defined within an @page
rule. Because margin boxes exist outside the normal document flow, they
cannot directly inherit DOM content.
The string-set property bridges this gap by acting like
a variable assignment. It copies the text value from an element in the
document tree and assigns it to a named string identifier.
Capturing Document Text
To capture text, you apply string-set directly to the
selector whose content you want to reuse, such as an
<h1> or <h2> tag:
h1 {
string-set: chapter-title content(text);
}In this example:
chapter-titleis the custom name chosen for the string.content(text)is a value function that extracts the plain text content of the<h1>element, ignoring any descendant HTML tags.
Other keyword variations for content() include:
content(before): Captures the generated content of the element's::beforepseudo-element.content(after): Captures the generated content of the element's::afterpseudo-element.content(): Captures the full content, including text and generated pseudo-element content.attr(attribute-name): Captures the value of a specific HTML attribute instead of inner text.
Displaying Captured Strings in Margin Boxes
Once a string is defined, it can be referenced inside any margin box
rule (such as @top-left, @top-center, or
@top-right) using the string() function:
@page {
@top-center {
content: string(chapter-title);
font-size: 9pt;
color: #555;
}
}Whenever the print layout engine encounters a new
<h1>, the value of chapter-title
updates. Pages printed after that point will reflect the updated
heading.
Handling Multiple Headings on a Single Page
If a page contains multiple elements that update the same named
string (for example, two <h2> headings on the same
page), you can control which occurrence the margin box displays using
page-scope arguments:
first: Uses the value of the first assignment on the page. (This is the default behavior if an assignment occurs on the page.)start: Uses the value in effect at the start of the page, even if an element on that page redefines the string later.last: Uses the value of the last assignment on the page.first-except: Uses the value of the string on pages where the element is not present, suppressing the header on the page where the heading actually appears (useful for title or chapter-start pages).
@page {
@top-right {
/* Displays the last section title encountered on the page */
content: string(section-title, last);
}
}Implementation Context
Native web browsers have limited support for CSS Paged Media margin
boxes and string-set. Consequently, this property is
primarily used alongside dedicated HTML-to-PDF print engines such as
PrinceXML, WeasyPrint, Antenna House Formatter, or polyfills like
Paged.js that implement CSS paged media standards.