HTML to PDF Conversion with CSS Page-Break Rules Explained
Control PDF pagination with CSS: force breaks, keep components together, configure pages, and troubleshoot why avoidance rules can still split content.
HTML-to-PDF pagination is CSS fragmentation: the renderer lays content into page boxes and chooses where it can flow from one page to the next. Use break-before: page or break-after: page to request a deliberate boundary, break-inside: avoid-page to discourage splitting a component, and @page to configure paper size and margins. Avoidance rules are constraints on break selection, not a promise that oversized content will fit on one page.
This guide explains the modern properties, their legacy aliases, practical CSS, renderer-dependent behavior, and how to diagnose pagination problems. The standards describe the controls, but the output still needs to be checked in the PDF renderer and version used in production.
1. Choose the right kind of page-break rule
| Goal | Modern CSS | Legacy alias | Effect |
|---|---|---|---|
| Start a section on a new page | break-before: page |
page-break-before: always |
Requests a forced page break before the box. |
| End a section at a page boundary | break-after: page |
page-break-after: always |
Requests a forced page break after the box. |
| Keep a component on one page where possible | break-inside: avoid-page |
page-break-inside: avoid |
Discourages a page break inside the box. |
| Discourage fragmentation generally | break-inside: avoid |
page-break-inside: avoid |
Discourages breaks in applicable fragmentation contexts, including pages. |
The modern properties use the fragmentation vocabulary. The older page-break-* declarations remain useful when compatibility with older renderers matters; their legacy values map to modern values, including always to page. If you support a specific set of PDF engines, check their behavior rather than assuming identical support.
2. Set the page size and margins separately
@page configures the page box. Break properties control where document content fragments. Keep these concerns separate so that changing paper dimensions does not require rewriting section-break rules.
@page {
size: A4;
margin: 18mm;
}
@media print {
.chapter {
break-before: page;
page-break-before: always;
}
.card,
figure {
break-inside: avoid-page;
page-break-inside: avoid;
}
p {
orphans: 3;
widows: 3;
}
}
This is a starting pattern, not a guarantee for every converter. The duplicated modern and legacy declarations express the same intent for engines that recognize one vocabulary or the other. Check the combined result in the renderer you deploy.
3. Force a break before or after content
Apply a forced break to the block at the boundary you want. For example, to make every chapter begin on a fresh page:
@media print {
.chapter {
break-before: page;
page-break-before: always;
}
}
For a break after a particular section instead, use:
@media print {
.appendix {
break-after: page;
page-break-after: always;
}
}
Forced values take precedence over avoidance constraints when the rules meet at a candidate boundary. Inspect adjacent elements too: a break can be affected by properties on boxes on either side and by enclosing context. If you see an unexpected blank page, look for a forced break on both adjacent blocks or for a forced break combined with content that already starts at the next page.
The fragmentation vocabulary also includes values such as left and right, and applicable specifications include recto and verso. These are for page-side or spread-aware layouts; ordinary reports and invoices usually need page. Verify support in your target PDF engine before relying on specialized values.
4. Keep a component together when possible
Use break-inside: avoid-page for a page-specific preference, or break-inside: avoid when you want a general fragmentation constraint. The legacy form is page-break-inside: avoid. Typical candidates are short cards, figures with captions, or compact table-like components.
@media print {
.summary-card,
figure {
break-inside: avoid-page;
page-break-inside: avoid;
}
}
Do not apply avoidance indiscriminately to a container taller than the printable page area. A renderer cannot keep oversized content intact within a smaller page. When ordinary break points are insufficient, the fragmentation rules allow constraints to be relaxed so content can continue; implementations may handle the resulting layout differently. A very tall component may overflow, split despite the preference, or paginate awkwardly.
For a large component, make smaller child sections breakable, reduce its height, or put a deliberate break at a sensible internal boundary. For tables, complex layout, flex or grid content, confirm the result in the exact engine and version that creates the PDF.
5. Prevent stranded lines with widows and orphans
orphans sets the minimum number of line boxes that should remain at the bottom of a fragment before a break. widows sets the minimum number that should appear at the top of the next fragment. They help avoid a lone line at either edge of a page.
@media print {
p {
orphans: 3;
widows: 3;
}
}
These properties influence break selection alongside other constraints. They do not guarantee a particular page count or exact break location, especially when the remaining page area cannot satisfy all constraints.
6. Build a complete HTML-to-PDF example
The following document uses print-specific CSS, starts each chapter on a new page, keeps compact figures together when possible, and sets line-count constraints. Save it as report.html and pass it to your chosen HTML-to-PDF renderer using that tool’s documented command or API.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Quarterly report</title>
<style>
@page {
size: A4;
margin: 18mm;
}
body {
font: 11pt/1.5 sans-serif;
color: #222;
}
@media print {
.chapter {
break-before: page;
page-break-before: always;
}
.chapter:first-of-type {
break-before: auto;
page-break-before: auto;
}
figure,
.summary-card {
break-inside: avoid-page;
page-break-inside: avoid;
}
p {
orphans: 3;
widows: 3;
}
}
</style>
</head>
<body>
<main>
<section class="chapter">
<h1>Overview</h1>
<p>A short introduction to the report.</p>
<figure>
<div>Chart or image content</div>
<figcaption>A compact caption kept with the figure where possible.</figcaption>
</figure>
</section>
<section class="chapter">
<h2>Results</h2>
<p>Replace this sample content with the report's results.</p>
<aside class="summary-card">A compact takeaway.</aside>
</section>
</main>
</body>
</html>
The :first-of-type example assumes the first chapter is the first section of its type among its siblings. If the document structure differs, target the opening chapter with a dedicated class instead. The sample also assumes the content is rendered with print styles active; confirm how your converter selects print media.
7. Understand why a requested break may look different
A break is selected from possible boundaries, and more than one rule can affect each boundary. The CSS Fragmentation and CSS 2.2 rules describe forced breaks, permitted unforced breaks, widows and orphans, and a fallback that relaxes constraints when necessary to prevent overflow. The standards do not prescribe a single uniquely correct choice from every set of allowed breaks. That is why a declaration is a layout control, not a pixel-exact pagination script.
- Content is taller than the page: an avoidance preference cannot make it fit intact.
- A neighboring rule forces a break: inspect
break-beforeandbreak-afteron both sides. - An ancestor constrains breaks: inspect the containing section and its fragmentation context.
- The renderer differs: engines and versions may implement paged-media and complex layout features differently.
- The content changed: fonts, images, loaded assets, and final page dimensions affect line wrapping and available space.
Validate a representative PDF with production fonts and assets at the final paper size. Review page boundaries, blank pages, figures and captions, tables, and any unusually tall blocks.
8. Troubleshoot common pagination problems
| Symptom | Likely cause | What to check or change |
|---|---|---|
| A chapter does not start on a new page | The rule is outside print styles, the selector misses, or the renderer does not apply the expected media mode. | Check the computed print styles, selector match, and renderer’s print-media setting. Try the legacy alias for an older target engine. |
| A card still splits | The card is taller than the remaining or full page area, or a conflicting rule or ancestor affects the break. | Check its rendered height, neighboring and ancestor rules, and whether the component can be shortened or divided. |
| A paragraph leaves one line at the page edge | Widow and orphan constraints are absent, unsupported, or impossible to satisfy with the available space. | Set reasonable widows and orphans values, then inspect the actual layout and surrounding content. |
| An unexpected blank page appears | A forced break is duplicated across adjacent elements, or a forced break occurs at content already aligned to a new page. | Inspect computed break-before/break-after values around the boundary and remove redundant forcing. |
| A figure separates from its caption | The keep-together rule is on the wrong wrapper, or the wrapped content cannot fit in the page area. | Put the figure and caption in one element and apply avoidance there; ensure the combined block is not oversized. |
| Pagination changes after deployment | The renderer version, fonts, assets, viewport or page setup differs. | Align those inputs with production and review the PDF produced by the deployed renderer version. |
| Legacy and modern declarations appear to conflict | The target engine’s alias handling or cascade differs from the assumption. | Inspect computed styles and test a minimal document in that engine; keep only the declarations needed for the support target. |
9. Performance, reliability, and cost considerations
CSS break rules themselves are layout instructions; the practical work is generating and checking the PDF in your rendering pipeline. Keep validation focused on representative documents and the exact renderer version, fonts, assets, and page dimensions used in production. If content is dynamic, ensure it has finished loading before conversion so late images or font changes do not shift pagination.
This standards guide does not establish a performance benchmark, reliability figure, or cost comparison for PDF engines. Those depend on your renderer, workload, and deployment. Measure conversion time and failure rates with your own documents, and account for the compute and operational costs of the renderer you choose.
10. Or skip the browser setup
If your goal is a PDF of a live web page, ScreenshotNeo provides a website screenshot API and MCP server. Its PDF options include paper size, margins, landscape orientation, and page ranges. A one-call request can capture a URL as PDF; see the API documentation for the request parameters and response details.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-d format=pdf \
-o page.pdf
For a reusable CSS template, custom HTML-to-PDF pipeline, or precise control over document structure, use the DIY method above. ScreenshotNeo is useful when the input is a live URL and you want to avoid managing browser capture setup. It removes cookie banners, popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed; and its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up free for 1,000 screenshots a month, no card required.
11. FAQ
Should I use break-before: page or page-break-before: always?
Use the modern property in new CSS. The legacy declaration is an alias useful when older renderers are in your support target. You can include both as a compatibility pattern, then verify the result in your engine.
Does break-inside: avoid guarantee that an element stays on one page?
No. It discourages an unforced break. It cannot make content larger than the available page area fit intact, and other constraints can affect where fragmentation occurs.
Does @page force a new page?
No. @page configures page-box properties such as size and margins. Use fragmentation properties to influence breaks in document content.
Why does the same CSS produce different PDFs?
Pagination depends on content and layout inputs as well as the renderer. Check the engine and version, fonts, assets, page dimensions, and print-media behavior.
Specifications and references
- W3C CSS Fragmentation Module Level 3 — fragmentation controls, break values, and legacy aliases.
- W3C CSS Paged Media Module Level 3 — page boxes and the
@pagecontext. - W3C CSS 2.2 Paged Media — legacy page-break rules, break constraints, and fallback behavior.
- MDN CSS fragmentation — an introduction to fragmentation and pagination.


