wkhtmltopdf page breaks not working: fixes that actually help

Updated July 2026 · applies to wkhtmltopdf 0.12.x (last release June 2020, repo archived)

Broken page breaks are the single most-cited wkhtmltopdf complaint: tables split mid-row, page-break-inside: avoid gets ignored, and the PDF that looked fine on your laptop breaks differently on the server. The root cause is the engine — a Qt WebKit snapshot from ~2015 with incomplete CSS fragmentation — but these workarounds fix the common cases without switching tools today.

1. Make layout deterministic first

Most “breaks move around randomly” reports are smart shrinking: wkhtmltopdf rescales the page to fit the paper, so break positions depend on rendered width and DPI — which differ between your dev machine and the server. Pin all of it:

# Predictable layout: stop rescaling, fix DPI, use print CSS, set the paper
wkhtmltopdf \
  --disable-smart-shrinking \
  --dpi 96 \
  --zoom 1 \
  --print-media-type \
  --page-size A4 \
  --margin-top 20mm --margin-bottom 20mm \
  invoice.html invoice.pdf

2. The inline-block wrapper trick

Old WebKit honours page-break-inside: avoid inconsistently on plain <div>s, but it never splits an inline-block — it moves the whole box to the next page. This is the most reliable keep-together primitive wkhtmltopdf has:

<!-- The inline-block wrapper trick: old WebKit moves inline-blocks to the
     next page as a unit, even where it ignores 'avoid' on a plain div. -->
<div style="display: inline-block; width: 100%; page-break-inside: avoid;">
  <h3>Line items</h3>
  <p>This block will never be split across pages.</p>
</div>

3. Tables: repeat headers, keep rows whole

/* Tables: repeat the header, keep rows whole */
table  { page-break-inside: auto; }
thead  { display: table-header-group; }  /* header repeats on every page */
tfoot  { display: table-footer-group; }
tr     { page-break-inside: avoid; page-break-after: auto; }

/* Manual break helper — force a break exactly where you want one */
.page-break {
  page-break-before: always;
  clear: both;   /* floats near a break confuse old WebKit; clear them first */
}

Two extra table gotchas: with border-collapse: collapse, borders that land exactly on a page boundary can disappear — if that bites you, switch to border-collapse: separate; border-spacing: 0 and put borders on cells. And rows taller than one page can never be kept whole; break the content into multiple rows.

4. Avoid flexbox and floats near breaks

/* wkhtmltopdf's engine predates flexbox-in-print and grid entirely.
   For anything that must survive a page break, use block or table layout. */

/* BAD in wkhtmltopdf — renders as a broken column or overlaps at breaks: */
.summary { display: flex; justify-content: space-between; }

/* GOOD — same visual result, fragmentation-safe in old WebKit: */
.summary { display: table; width: 100%; }
.summary > div { display: table-cell; }

5. Know when you’re at the engine’s limit

If you need break-after: avoid (keep headings with their content), CSS grid, orphans/widows that behave, or breaks inside flex layouts — wkhtmltopdf cannot do it and never will; the project is archived. Modern Chromium implements the full fragmentation spec: see our complete guide to page-break CSS for what becomes possible after you migrate.

FAQ

Why does wkhtmltopdf ignore page-break-inside: avoid?

wkhtmltopdf embeds a Qt WebKit engine frozen around 2015 with incomplete CSS fragmentation support. page-break-inside: avoid is honoured only on simple block-level elements — not reliably on table rows, floated content, or inline formatting contexts. The workarounds on this page reshape your markup into the cases the old engine handles.

What does --disable-smart-shrinking actually do?

"Smart shrinking" rescales the rendered page to fit the paper width, changing the effective pixel-to-millimetre ratio. That rescaling is why breaks land in different places on your laptop versus the server. Disabling it makes layout math predictable; pair it with --dpi 96 and explicit --page-size.

Will these fixes make wkhtmltopdf reliable?

They fix the most common failures, but the engine is archived and unmaintained — flexbox, grid and the modern break-* properties will never work. Treat these as a bridge while you migrate to a Chromium-based renderer, where page-break CSS works as specified.

…or skip all of this with one API call. NippyPDF is a managed Chromium rendering core behind a single POST /v1/pdf — no browser fleet, no page-break roulette, around $0.003/document.

Try the live demoJoin the waitlistModern page-break CSS guide (Chromium) →