The page box / @top-center and the margin boxes
How to put a running header in a PDF with CSS
The page margin boxes are sixteen named regions around the page box, such as @top-center and @bottom-right, each of which can hold generated content that repeats on every page.
What it is for
This is the specification's answer to running headers and footers, and it is elegant: the header is CSS, it lives with the rest of the document's styling, and it can pull text from the content with string-set.
Support: Does nothing in a browser-based render
Not implemented by browser engines. Writing @top-center produces no error and no header. Dedicated print engines like PrinceForm and WeasyPrint do implement it, which is why so much writing about it exists and so little of it works in a browser-based render.
What to write instead
The specification syntax is shown first so it is recognisable, followed by the approach that produces the result you were after.
/* The specification version. Silent no-op in a browser-based render. */
@page {
@top-center { content: "Statement for March 2026"; }
@bottom-right { content: counter(page) " of " counter(pages); }
}
/* What works: header and footer templates passed with the render, styled
entirely inline because they get none of the document's CSS. */
{
"options": {
"displayHeaderFooter": true,
"margin": { "top": "20mm", "bottom": "18mm" },
"headerTemplate": "<div style=\"font-size:9pt;padding:0 16mm;color:#555\">Statement for March 2026</div>",
"footerTemplate": "<div style=\"font-size:9pt;padding:0 16mm;text-align:right\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>"
}
}The mistake people make
Spending an afternoon on this before discovering it is not implemented. The tell is that nothing appears and nothing errors, which is what unimplemented CSS always looks like.
Frequently asked
Does @top-center and the margin boxes work when generating a PDF?
Does nothing in a browser-based render. Not implemented by browser engines. Writing @top-center produces no error and no header. Dedicated print engines like PrinceForm and WeasyPrint do implement it, which is why so much writing about it exists and so little of it works in a browser-based render.
How would I know if it were not working?
You would not, from the CSS. Unimplemented and unmatched CSS both fail silently, which is why the reliable test is to set a deliberately extreme value and see whether anything changes. If a 40mm margin looks the same as an 18mm one, the rule is not reaching the page.
Related properties
Things that come up in the same part of a document stylesheet.
How to use the @page rule for PDF output
@page. Works in a browser-based render.
How to set the PDF page size in CSS
size. Works in a browser-based render.
How to set PDF page margins in CSS
margin (in @page). Works in a browser-based render.
How to style the first page differently in a PDF
@page :first, :left, :right. Works in a browser-based render.
How to make one section landscape in a portrait PDF
page (named pages). Only in dedicated print engines.
Every property, with its support status
The full reference, grouped by what part of the page it touches.
Paste the CSS and see what the rendered page does with it.