Page breaks in HTML to PDF: the CSS that actually works
Rows split across pages, headings orphaned at the bottom, cards cut in half. The four CSS properties that fix it in Chromium-based renderers, with the traps.
Updated 31 August 2026
Page breaks are the first thing that looks wrong when a web page becomes a document. The browser laid it out as one infinite column; the PDF has to cut it into A4 slices, and it cuts wherever the slice ends unless you say otherwise.
The four properties
- `break-inside: avoid` on anything that must not be split: table rows, cards, figure + caption pairs.
- `break-before: page` on the element that should start a new page — a chapter heading, an appendix.
- `break-after: avoid` on headings, so a heading never sits alone at the bottom with its paragraph on the next page.
- `orphans` and `widows` (minimum lines at the bottom and top of a page) for long text; 3 is a sensible value.
The older `page-break-*` names still work and are what most examples use. Chromium treats them as aliases.
Tables
A table that spans pages needs `thead { display: table-header-group }` so the header repeats, and `tr { break-inside: avoid }` so no row is cut mid-line. Set both; the second is the one people forget.
thead { display: table-header-group; }
tr, td, th { break-inside: avoid; }
What silently breaks it
- `overflow: hidden` or a fixed `height` on an ancestor: the renderer cannot break inside a box that clips, so it either overflows or squashes.
- Flexbox containers: children of a flex row are laid out together and break as a unit. Put `break-inside: avoid` on the row, not the cells.
- `position: fixed` elements repeat on every page — useful for a watermark, surprising for a nav bar you forgot to hide in print.
Print stylesheet
Everything above belongs in `@media print { … }` or in a stylesheet loaded only for the PDF. Hide navigation, expand collapsed sections, and turn link text into visible URLs if the document will be printed on paper:
@media print {
nav, .no-print { display: none; }
a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 90%; }
}
Test with real content
Page breaks only show up with enough content to fill a page. Render with your longest realistic document, not a two-line fixture — and check the last page, where a lone footer row is the classic leftover.
Try it: convert HTML to PDF in the browser, or get a free API key — 50 documents a month.
More guides
Writing HTML templates for PDF: a style guide (Jinja, Django, Handlebars)
Templates that render well as PDFs follow a few rules: fixed page geometry, no external state, defensive filters, print CSS. Examples in Jinja and Django syntax.
Issuing 5,000 course certificates in one afternoon
A spreadsheet of names, one landscape template, batch requests of 100, and signed links per student. The full workflow including naming, verification codes and delivery.
Generating receipts at checkout without slowing the checkout
The receipt PDF should never sit between the customer and the order confirmation. A pattern: confirm first, render asynchronously, attach when ready.
URL-to-PDF and SSRF: how a PDF renderer becomes an attack surface
A renderer that fetches URLs can be pointed at your internal network. The attacks, the defences, and what to demand from a PDF API vendor.