Generating PDFs from HTML: The Ultimate Guide

Why struggle with complex PDF libraries when you already know HTML and CSS? Learn how to convert your web designs into professional documents.

📋 Table of Contents

Why HTML to PDF?

Historically, generating PDFs required learning specialized libraries like libpdf, ReportLab, or PDFKit. These tools typically have their own drawing APIs, meaning you have to "draw" text at specific X,Y coordinates.

This is tedious and brittle. If you want to change a font size, you might have to recalculate the position of everything below it.

The modern approach is different: Use HTML and CSS to design your document. You already know these tools. Then, use a browser engine to "print" that HTML to a PDF file.

Print Stylesheets (CSS)

Before you generate a PDF, you need to make sure your HTML looks good on paper. This is where @media print comes in.

@media print {
    /* Hide navigation and buttons */
    nav, footer, .btn {
        display: none !important;
    }

    /* Ensure text is black for saving ink */
    body {
        color: #000;
        background: #fff;
    }

    /* Improve link readability */
    a {
        text-decoration: none;
    }
}

Using Puppeteer (Node.js)

Puppeteer is the gold standard for HTML-to-PDF conversion in the Node.js ecosystem. It uses headless Chrome to render the page.

import puppeteer from 'puppeteer';

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    
    // Load your HTML content or URL
    await page.setContent(`<h1>Invoice #101</h1><p>Top-notch service</p>`);
    
    // Generate PDF
    await page.pdf({
        path: 'invoice.pdf',
        format: 'A4',
        printBackground: true,
        margin: {
            top: '20px',
            bottom: '20px'
        }
    });

    await browser.close();
})();

Using Python (WeasyPrint vs. Playwright)

In Python, you have two main options:

1. WeasyPrint: A dedicated visual rendering engine for HTML/CSS to PDF. It doesn't use a browser. It's lightweight but doesn't support JavaScript or modern CSS features (like Grid or Flexbox perfectly).

2. Playwright (Python): Uses a real browser engine (Chromium/WebKit). It supports everything Chrome supports.

from playwright.sync_api import sync_playwright

def run():
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto('https://example.com/report')
        page.pdf(path="report.pdf", format="Letter")
        browser.close()

if __name__ == "__main__":
    run()

The API Approach (SnapAPI)

Managing headless browsers in production is painful. They consume huge amounts of RAM, can crash unexpectedly, and require constant updates.

Using a managed API simplifies this to a single HTTP request.

# POST request to SnapAPI
curl -X POST "https://snapapi.alterra-solutions.com/v1/pdf" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Certificate of Completion</h1>",
    "api_key": "YOUR_KEY",
    "format": "A4",
    "print_background": true
  }' -o certificate.pdf

Pro Tips for Page Breaks

One of the hardest parts of PDF generation is handling page breaks efficiently. You don't want an image or a table row to be cut in half.

Use modern CSS break properties:

/* Force a break before this element */
.section-start {
    break-before: page;
}

/* Prevent an element from breaking inside */
.card, tr {
    break-inside: avoid;
}

Conclusion

Stop generating PDFs pixel-by-pixel. Embrace the power of the web platform. Design with HTML/CSS, test in your browser, and render with Puppeteer or an API like SnapAPI for reliable results.

Generate PDFs Effortlessly

SnapAPI supports high-fidelity PDF generation from HTML or URLs.

Start Generating PDFs →