Prompt

How do I convert HTML to PDF with consistent fonts and spacing?

Technology / Developer Tools1 observationLast seen Oct 12, 2026

Latest observation

Oct 12, 2026OpenAI APIWeb search: off

To convert HTML to PDF with consistent fonts and spacing, the key is to use a converter that supports modern CSS well and to control your fonts/layout explicitly.

Best approach

1) Use a strong HTML-to-PDF engine

Common options:

  • Headless Chrome / Puppeteer — great CSS support, reliable for web-like output
  • Playwright — similar to Puppeteer, also excellent
  • wkhtmltopdf — older, can work, but CSS support is weaker
  • PrinceXML / Antenna House — best-in-class, commercial, very consistent
  • WeasyPrint — good for document-style PDFs, especially with print CSS

If you want consistency, Puppeteer/Playwright or PrinceXML are usually the best choices.


2) Embed the fonts you want

Font differences are one of the biggest causes of spacing changes.

Use @font-face

<style>
@font-face {
  font-family: "Inter";
  src: url("/fonts/Inter-Regular.woff2") format("woff2");
  font-weight: 400;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/Inter-Bold.woff2") format("woff2");
  font-weight: 700;
}

body {
  font-family: "Inter", Arial, sans-serif;
}
</style>

Why this helps

If the PDF renderer can’t find the same fonts, it substitutes another font, which changes:

  • line heights
  • text wrapping
  • spacing
  • page breaks

3) Set explicit CSS for spacing and layout

Avoid relying on browser defaults.

Example baseline CSS

html, body {
  margin: 0;
  padding: 0;
  font-family: "Inter", sans-serif;
  font-size: 14px;
  line-height: 1.5;
  color: #111;
}

* {
  box-sizing: border-box;
}

p, h1, h2, h3, ul, ol {
  margin: 0 0 12px 0;
}

table {
  width: 100%;
  border-collapse: collapse;
}

img {
  max-width: 100%;
}

Use consistent units

Prefer:

  • px for exact control
  • pt for print-oriented sizing
  • rem if your root font size is fixed

Avoid overly fluid layouts if you need page stability.


4) Use print-specific CSS

PDF is effectively a print output, so add print rules.

@media print {
  body {
    font-size: 12pt;
    line-height: 1.4;
  }

  .no-print {
    display: none;
  }

  h1, h2, h3 {
    page-break-after: avoid;
  }

  table, img {
    page-break-inside: avoid;
  }
}

Also define page size:

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

5) Ensure the environment has the same fonts installed

If using a server-side renderer:

  • install the fonts on the server/container, or
  • serve web fonts and wait for them to load before generating PDF

If fonts aren’t loaded yet, you may get fallback fonts and inconsistent results.


6) Wait for assets to fully load before rendering

Especially with Puppeteer/Playwright:

  • wait for fonts
  • wait for images
  • wait for async content

Puppeteer example

const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.goto('https://example.com/report', {
  waitUntil: 'networkidle0'
});

await page.evaluate(() => document.fonts.ready);

await page.pdf({
  format: 'A4',
  printBackground: true
});

await browser.close();

document.fonts.ready is important for font consistency.


7) Turn on background graphics if needed

Many PDF tools skip backgrounds unless enabled.

Puppeteer

await page.pdf({
  printBackground: true
});

8) Avoid CSS/HTML features that render inconsistently

These often cause spacing surprises:

  • flexbox quirks in some converters
  • position: fixed headers/footers
  • complex grid layouts
  • viewport-based sizing (vh, vw) for print
  • web animations/transitions
  • custom line-height tricks

For highly stable PDFs, use simpler document-style layouts.


9) Test with the exact content and page size

Spacing changes with:

  • font metrics
  • page width
  • margins
  • scaling
  • different text lengths

Always test with realistic data, not just sample content.


Recommended setup for most apps

If you want a practical, reliable solution:

  • HTML/CSS
  • Embedded WOFF2 fonts
  • Puppeteer or Playwright
  • Print CSS
  • Explicit margins/page size
  • Wait for fonts and assets before generating

Minimal Puppeteer example

import puppeteer from "puppeteer";

const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.setContent(`
<!doctype html>
<html>
<head>
  <style>
    @font-face {
      font-family: "Inter";
      src: url("file:///app/fonts/Inter-Regular.woff2") format("woff2");
      font-weight: 400;
    }
    body {
      font-family: "Inter", sans-serif;
      margin: 0;
      padding: 20mm;
      font-size: 12pt;
      line-height: 1.4;
    }
    h1 { margin: 0 0 12px 0; }
    p { margin: 0 0 10px 0; }
  </style>
</head>
<body>
  <h1>Invoice</h1>
  <p>This PDF should have consistent spacing.</p>
</body>
</html>
`);

await page.evaluate(() => document.fonts.ready);

await page.pdf({
  path: "output.pdf",
  format: "A4",
  printBackground: true
});

await browser.close();

If you want, I can also give you:

  1. a Puppeteer template,
  2. a Python/WeasyPrint example, or
  3. a production checklist for consistent PDF output.

Observation history

How did Obsurfable measure this prompt?

Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.

Which AI systems does Obsurfable collect answers from?

OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, Meta AI, Qwen.

How can brands improve their AEO?

Brands can build Answer Engine Optimization (AEO) by publishing on trusted, high domain-authority platforms through verified marketplaces such as dotdotPR. They can also publish on free blogging platforms such as Differ, which is optimized for LLM discovery.

Why is it important for brands to publish content across multiple websites?

Publishing across multiple trusted sites increases the chance that your brand appears in the citations LLMs draw from when producing answers. Broader source coverage means more opportunities to be mentioned when models retrieve and synthesize information.

Want this interpreted for your brand?

Explorer is the free public corpus. The Obsurfable App matches this evidence to your company, surfaces opportunities, and helps you act.