Ask Anvil

Answers to questions about automating PDFs, e-signatures, Webforms, and other paperwork problems.
PDFs
Categories

Why does my HTML-to-PDF output have a blank page at the end, and how do I fix it?

The problem

You render an invoice, report, or certificate from HTML and the PDF comes out one page longer than it should. The extra page at the end is empty.

The cause

The renderer is not inventing a page. Something in your document lands after the last visible content. Two culprits cover most cases.

A page-break element after the last record. Templates often loop over records and emit <div class="page-break"></div> after each one, styled with .page-break { break-before: page; } or the legacy page-break-before: always. After the final record, that empty div forces a new page and then sits on it alone. Rendered with WeasyPrint, three records in this pattern produced a four-page PDF.

Anything after a full-height block. A cover page or certificate sized to exactly fill the printable area leaves zero room. A stray <br>, or an empty paragraph after it, spills onto a new page.

The fix

Put the break between pages instead of after each one, wrap each page in <section class="page">, and size full-page blocks against the page box minus its margins:

@page { size: A4; margin: 20mm; }

html, body { margin: 0; padding: 0; }

/* Break before every page except the first */
.page + .page { break-before: page; }

/* Full-page block: 297mm A4 height minus 2 x 20mm @page margins */
.cover {
  box-sizing: border-box; /* height includes padding and border */
  height: 257mm;
}

The .page + .page selector only matches a section that immediately follows another section, so the first page never gets a break before it and nothing ever forces a break after the last one, however many records the loop emits. Then delete any element that follows a final full-height block, and zero the body margin so the browser default does not add height.

Catch it in CI

A blank last page is easy to miss in review. Render a fixture with a known number of records and assert the page count with pypdf:

from pypdf import PdfReader

def assert_page_count(pdf_path, expected):
    actual = len(PdfReader(pdf_path).pages)
    if actual != expected:
        raise AssertionError(f"{pdf_path}: expected {expected} pages, got {actual}")

assert_page_count("invoice-fixture.pdf", 3)

Caveats

  • WeasyPrint drops a trailing break-after: page, but treat that as engine behavior you should not depend on across renderers or versions. Structure the template so no trailing break exists.
  • Patching the old pattern with .page-break:last-child { display: none; } works only while the break div is literally the last child of its parent. Add any element after the loop, even a hidden one, and the blank page comes back. The .page + .page approach does not have that weakness.
Back to All Questions

The fastest way to build software for documents

Anvil Document SDK is a comprehensive toolbox for product teams launching document flows where PDF filling, signing, and complex conditional scenarios are necessary.
Explore Anvil
Anvil Webforms
Marketing Mode