Paged media
Changed in 1.22.0: Page rules and margin boxes.
Page rules and margin boxes Changed in 1.22.0
@page rules set the page size, margins and background, and their margin boxes (@top-left, @top-center,
@bottom-right and the other thirteen) print headers and footers with counter(page) and counter(pages), chosen
per page with :first, :left and :right. Those three can also change the page's size, margins and background:
@page :first { margin-top: 70mm } leaves room for a letterhead on page 1 only, and mirrored :left and :right
margins give a bound booklet a wider inner margin, and each page is laid out at its own content width. The first page
is a right page; in a right-to-left document (dir="rtl" on <html>) it is a left page, and PDF viewers are told the
pages run right to left. A border and padding on the @page box are drawn inside the margins, with the content inside
them, and the page's background images cover the whole sheet, as Chrome prints them (the images are positioned in the
page box, as CSS Paged Media 3 says). On top of that:
- Named pages:
page: wideputs an element on pages styled by@page wide { ... }, with their own size, orientation, margins, background and margin boxes. Content on another named page starts a new page, so a landscape table or a full-bleed cover can sit between portrait pages. - Running headers:
string-setcopies text from the document (content(),attr(), strings and counters) into a named string, andstring(name)shows it in a margin box: the chapter title in the page header, say. As in the spec,string(name, first | start | last | first-except)picks which value a page shows. - Tables of contents:
target-counter(attr(href), page)shows the page number of the element a link points to, andleader(dotted)(orsolid,space, or a string) fills the space before it.target-text()shows the linked element's text. The document is laid out again with the numbers it finds, so they are always right. - Page count in the content:
counter(pages)works anywhere, not only in margin boxes, as in Prince: "This report has 12 pages" on its first page. - Sections:
-pdfpecker-target-pages(attr(href), first | last | count | current)gives the first or last page of the element a link points to, how many pages it covers, or the page counted from its first (with an optional counter style, astarget-counter()takes): "Chapter 3, pages 12–17" in a table of contents, or "page 2 of 6" within a section. In a sticky header or footer,{section-page:id}(the id percent-encoded) is the page within that section.
@page { size: A4; margin: 20mm;
@top-center { content: string(chapter) }
@bottom-right { content: "Page " counter(page) " of " counter(pages) } }
@page cover { margin: 0; background: #1d3557; @top-center { content: none } @bottom-right { content: none } }
@page wide { size: A4 landscape }
.cover { page: cover }
.wide-table { page: wide }
h2 { string-set: chapter content(); break-before: page }
nav a::after { content: leader(dotted) target-counter(attr(href), page) }
Chrome supports named pages and margin boxes, but not running strings, target-counter(), leader(), the page count
in the content or section page numbers; -pdfpecker-target-pages() is PdfPecker's own.
Footnotes
float: footnote moves an element to the footnote area at the bottom of the page its call is on, as in CSS Generated
Content for Paged Media. The footnote counter numbers them; ::footnote-call styles the number in the text (a
superscript by default) and ::footnote-marker the number before the note. @page { counter-reset: footnote }
restarts the numbering on every page, and @footnote inside @page styles the area with margins, padding, borders, a
background and max-height. footnote-display: inline runs short notes together on one line, and
footnote-policy: line moves the line with the call to the next page when its note does not fit. A long note
continues on the next page. Each call links to its note, and tagged PDFs mark the notes as Note (PDF/UA-1) or
FENote (PDF/UA-2).
.note { float: footnote; font-size: 8pt }
.note::footnote-call { content: "[" counter(footnote) "]"; vertical-align: baseline }
@page { @footnote { border-top: 0.5pt solid #999; padding-top: 4pt; margin-top: 8pt } }
<p>Paid on the last banking day<span class="note">Or the day before a holiday.</span>.</p>
Running header and footer from HTML
An element with the data-sticky-pdf-header or data-sticky-pdf-footer attribute is
taken out of the flow and drawn at the top or bottom of every page, and the page content flows in the space between.
Inside it, {page} and {total-pages} (or {pages}) are replaced with the page number and page count. An optional
height attribute (height="17mm") reserves at least that much space.
<header data-sticky-pdf-header height="17mm">ACME Ltd · Payslip</header>
<main>...</main>
<footer data-sticky-pdf-footer height="12mm">Page {page} of {total-pages}</footer>
An element with data-sticky-pdf-first-header or data-sticky-pdf-first-footer takes the place of the running header
or footer on the first page only: a letterhead on page one and a slim header after it, or, left empty, no header or
footer on page one at all. The content on page one uses the space its own bands leave.
<header data-sticky-pdf-first-header height="40mm"><img src="letterhead.png" alt="ACME Ltd"></header>
<header data-sticky-pdf-header height="12mm">ACME Ltd · Offer 2041</header>
<footer data-sticky-pdf-first-footer></footer>
<footer data-sticky-pdf-footer>Page {page} of {total-pages}</footer>
A band with data-sticky-pdf-page="name" is the header or footer of the pages of that named page
instead of the document's bands, and a first-page band with it shows on the first page of each run of that page.
Pages without bands of their own keep the document's. One HTML document can so hold a cover, a portrait letter and a
landscape appendix, each with its own size, margins, header and footer, while page numbers run on through the whole
document.
<style>
@page appendix { size: A4 landscape }
.appendix { page: appendix }
</style>
<footer data-sticky-pdf-footer>Page {page} of {total-pages}</footer>
<footer data-sticky-pdf-footer data-sticky-pdf-page="appendix">Appendix · page {page}</footer>
Shrink to fit
When content sticks out past the right edge of the page area, Chrome prints the page laid out as much wider as the
content reaches and drawn smaller, and PdfPecker does the same. A box or image wider than the page, a long word or
white-space: nowrap text, a Bootstrap .row without a .container (its negative margin), a relative offset, a
translateX() or an absolutely positioned box can each widen the layout, by at most 1.5 times (drawn at 67%), on top
of Scale. The paper keeps its size and the margins keep theirs. As in Chrome, overflow to the left, content inside an
overflow: hidden or clip box (other than html and body) and position: fixed boxes do not count.
Set ShrinkToFit = false to lay the document out at the page width as before 1.18.0, with the overflow running into
the margin; an image wider than the page is then scaled down on its own.
var pdf = HtmlToPdf.Convert(html, new PdfOptions { ShrinkToFit = false });