Handling Page Breaks in PDF Generation
Master the art of page breaks in HTML to PDF conversion. Learn how to control where content splits and keep important elements together.
Handling Page Breaks in PDF Generation
One of the most challenging aspects of HTML to PDF conversion is controlling page breaks. Poor page break handling can result in:
- Tables split awkwardly mid-row
- Headers separated from their content
- Broken layouts and orphaned text
- Poor readability
Let's master page breaks once and for all.
CSS Page Break Properties
CSS provides several properties for controlling page breaks:
/* Force a page break before an element */
.new-chapter {
page-break-before: always;
}
/* Prevent page breaks inside an element */
.keep-together {
page-break-inside: avoid;
}
/* Force a page break after an element */
.section-end {
page-break-after: always;
}Modern CSS (Better Browser Support)
The newer break- properties are recommended:
.new-chapter {
break-before: page;
}
.keep-together {
break-inside: avoid;
}
.section-end {
break-after: page;
}SyntaxDoc supports both the legacy page-break-* and modern break-* properties.
Common Scenarios
1. Keep Tables Together
Never split a table header from its content:
table {
break-inside: avoid;
}
/* For large tables that must span pages */
table.large {
break-inside: auto;
}
thead {
display: table-header-group; /* Repeat on each page */
}
tr {
break-inside: avoid;
break-after: auto;
}2. Keep Headings with Content
Prevent headings from appearing alone at the bottom of a page:
h1, h2, h3, h4, h5, h6 {
break-after: avoid;
break-inside: avoid;
}
/* Also keep the first paragraph with the heading */
h1 + p, h2 + p, h3 + p {
break-before: avoid;
}3. Invoice Line Items
Keep invoice items properly grouped:
.invoice-items table {
break-inside: auto;
}
.invoice-items tr {
break-inside: avoid;
}
.invoice-totals {
break-inside: avoid;
break-before: avoid; /* Keep with last item */
}4. Multi-Column Layouts
Handle columns carefully:
.column {
break-inside: avoid;
page-break-inside: avoid;
}
.column-break {
break-after: column;
}Advanced Techniques
Widows and Orphans
Control how many lines must appear at page breaks:
p {
orphans: 3; /* Minimum lines at bottom of page */
widows: 3; /* Minimum lines at top of page */
}Orphan: The first line of a paragraph appearing alone at the bottom of a page
Widow: The last line of a paragraph appearing alone at the top of a page
Smart Page Margins
Add extra space before page breaks:
@page {
margin: 20mm;
@top-center {
content: "Document Title";
}
}
/* First page different */
@page :first {
margin-top: 50mm;
}Content-Aware Breaks
Use data attributes to control breaks dynamically:
<div class="section" data-keep-together="true">
<!-- Content that must stay together -->
</div>[data-keep-together="true"] {
break-inside: avoid;
}The SyntaxDoc Advantage
SyntaxDoc includes intelligent page break handling that goes beyond standard CSS:
Automatic Table Splitting
{
"options": {
"smartPageBreaks": true,
"tableHandling": "auto-split"
}
}This automatically:
- Repeats table headers on new pages
- Prevents single rows from being orphaned
- Adds continuation markers
- Maintains table styling across breaks
Smart Content Flow
{
"options": {
"smartPageBreaks": true,
"orphanControl": "strict"
}
}Features:
- Detects related content (headings + paragraphs)
- Prevents awkward splits
- Optimizes whitespace
- Maintains visual hierarchy
Testing Your Page Breaks
Always test with various content lengths:
// Test with different amounts of content
const testCases = [
{ items: 5, description: "Single page" },
{ items: 25, description: "Multi-page" },
{ items: 100, description: "Large document" },
];
for (const test of testCases) {
const html = generateInvoice({ itemCount: test.items });
const pdf = await generatePDF(html);
console.log(`${test.description}: ${pdf.pages} pages`);
}Best Practices Checklist
✅ Do
- Test with various content lengths
- Use
break-inside: avoidon critical elements - Keep related content together
- Use appropriate margins
- Test headers and footers across pages
- Consider mobile/print preview during development
❌ Don't
- Force page breaks unnecessarily
- Use absolute positioning near page boundaries
- Ignore table headers on continuation pages
- Forget about widows and orphans
- Use overly complex nested layouts
Common Issues and Solutions
Issue: Table Rows Split Across Pages
Solution:
tr {
break-inside: avoid;
page-break-inside: avoid;
}Issue: Large Images Causing Breaks
Solution:
img {
max-height: 80vh; /* Prevent images from forcing breaks */
break-inside: avoid;
}Issue: Floated Elements Causing Issues
Solution:
/* Clear floats before page breaks */
.clearfix::after {
content: "";
display: table;
clear: both;
page-break-after: always;
}Example: Complete Invoice Page Breaks
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 0;
padding: 20mm;
}
.invoice-header {
break-inside: avoid;
break-after: avoid;
}
.invoice-items table {
width: 100%;
break-inside: auto;
}
.invoice-items tr {
break-inside: avoid;
}
.invoice-items thead {
display: table-header-group;
}
.invoice-totals {
break-inside: avoid;
break-before: avoid;
margin-top: 2rem;
}
.invoice-terms {
break-before: page;
}
</style>
</head>
<body>
<div class="invoice-header">
<!-- Header content -->
</div>
<div class="invoice-items">
<table>
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<!-- Items -->
</tbody>
</table>
</div>
<div class="invoice-totals">
<!-- Totals -->
</div>
<div class="invoice-terms">
<!-- Terms and conditions on new page -->
</div>
</body>
</html>Learn More
Start generating PDFs with perfect page breaks using SyntaxDoc's smart algorithms.