Styling pages for PDF output
The small set of CSS techniques you actually need to get clean PDFs out of the website capture API: @media print, page breaks, @page, and the gotchas.
When Converterer renders your page to PDF, the browser switches from a continuous scrollable canvas to a sequence of fixed-size pages. That single change is the source of every “looks fine on screen, looks wrong in the PDF” surprise.
The CSS you need to control it is small and well-supported in 2026. The rules below cover most cases. For the deeper treatment, see our blog post on Print CSS basics in 10 minutes.
Start with @media print
Wrap any rule you only want to apply when rendering to PDF in @media print. Converterer’s renderer respects this media query by default.
@media print {
.site-nav,
.cookie-banner,
.chat-widget {
display: none;
}
body {
font-size: 11pt;
color: #000;
background: #fff;
}
}
Three things to notice:
- Use
ptfor type sizes. Print and screen resolutions aren’t the same. - Force black text on white background. Avoid relying on dark-mode defaults.
- Hide chrome. Nav, banners, chat widgets, share buttons, anything interactive on screen should disappear in print.
If you want a rule to apply to both screen and print but with different values, use the cascade. There’s no “screen-only” media query you need to remember, the default is screen.
Need the screen layout instead?
If your source page is built without print styles and you want Converterer to render the on-screen view, pass screen: true in the API request. The renderer then emulates the screen media type instead of print.
Control page breaks
The most common print bug is content getting awkwardly chopped across pages. CSS has three properties for this:
.section-heading {
break-before: page; /* start this element on a new page */
}
.invoice-footer {
break-after: page; /* force a new page after this element */
}
.do-not-split {
break-inside: avoid; /* don't split this element across pages */
}
The older page-break-before, page-break-after, and page-break-inside still work, but the unprefixed break-* properties have been the recommended form since 2020.
Practical recipe for a multi-page report:
@media print {
h1, h2 { break-after: avoid; } /* don't orphan a heading at the bottom */
table { break-inside: avoid; } /* keep tables together where possible */
figure { break-inside: avoid; } /* don't split a chart from its caption */
.chapter { break-before: page; } /* each chapter starts a new page */
}
Repeat table headers across pages
Long tables span multiple pages, and they’re unreadable if the header row only appears on page one. Use <thead> (not just a <tr> with bold cells) and the renderer repeats the header on every page automatically:
<table>
<thead>
<tr><th>SKU</th><th>Description</th><th>Price</th></tr>
</thead>
<tbody>
<tr><td>...</td><td>...</td><td>...</td></tr>
</tbody>
</table>
No extra CSS needed.
Avoid stranded lines
An orphan is a single line stranded at the bottom of a page; a widow is a single line at the top of the next. Both look bad:
@media print {
p {
orphans: 3; /* at least 3 lines must stay at the bottom */
widows: 3; /* at least 3 lines must stay at the top */
}
}
Three is a sensible default.
Print backgrounds and colours
Browsers strip background colours and images by default for print. To force them through, use print-color-adjust: exact:
.receipt-header {
background: #f0f0f0;
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
The color-adjust shorthand is deprecated, print-color-adjust is the current name.
Control the page itself
The @page rule controls page size, margins, and headers/footers that live in the page margins:
@page {
size: A4;
margin: 25mm 20mm;
@top-center {
content: "Quarterly Report, Q1 2026";
font-size: 9pt;
color: #666;
}
@bottom-right {
content: "Page " counter(page) " of " counter(pages);
font-size: 9pt;
}
}
Available margin boxes are @top-left, @top-center, @top-right, @bottom-left, @bottom-center, @bottom-right, plus -corner variants.
counter(page) and counter(pages) are built in. You don’t have to declare them.
For most use cases, prefer the header_template and footer_template API parameters over @page margin boxes, the templates have access to the full set of dynamic tokens (pageNumber, totalPages, date, title, url) and don’t require any source-page changes. See Header & footer templates.
Web fonts
Web fonts loaded via @font-face work as they do on screen, with one caveat: give the renderer time to finish loading them before snapshotting. The most reliable trigger is wait_css_selector pointing at an element that only renders after document.fonts.ready, or a CSS class your page applies once fonts have loaded. See Parameters: timing in practice.
The renderer also ships with a standard system font set if you want to skip web fonts entirely.
Preview without round-tripping the API
You don’t need to generate a PDF every time you tweak a rule. In Chrome DevTools:
- Open the Rendering panel (Command Menu → “Show Rendering”).
- Find Emulate CSS media type.
- Set it to print.
Your @media print rules now apply live in the viewport. Firefox and Safari have equivalents.
This is the single biggest productivity boost for print-CSS work.
A minimal print stylesheet that covers most cases
@media print {
/* hide the parts of the page that aren't content */
.site-nav, .footer-cta, .chat-widget { display: none; }
/* set print-friendly type and color */
body { font-size: 11pt; color: #000; background: #fff; }
/* control page breaks */
h1, h2 { break-after: avoid; }
table, figure { break-inside: avoid; }
/* expand link URLs after the anchor text */
a[href]::after { content: " (" attr(href) ")"; font-size: 90%; }
a[href^="#"]::after,
a[href^="javascript:"]::after { content: ""; }
/* avoid stranded lines */
p { orphans: 3; widows: 3; }
}
@page {
size: A4;
margin: 25mm 20mm;
}
Drop that into any HTML page you’re sending to the capture API and the output will be 90% of the way there.
Going further
For complex paginated layouts (running headers that pull content from <h1>s, footnotes, cross-references, column-balanced multi-column overflow) the paged.js project is worth a look. We cover when it’s worth reaching for in Modern HTML to PDF conversion.