Fix Cut-Off Content in HTML to PDF Conversion
Find why HTML content is cut off in a PDF, then fix print CSS, page sizing, margins, and page breaks with runnable browser examples.
To fix cut-off content in an HTML-to-PDF conversion, inspect the page in print media, align the renderer’s paper size and margins with your CSS @page rule, and remove layout constraints that clip content. Then use page-break rules only where they suit the content. A PDF can use different CSS from the screen page: Puppeteer and Playwright generate PDFs with print CSS by default. The exact cause depends on your HTML, CSS, renderer, and PDF options.
This guide covers Chromium-based Puppeteer and Playwright. Other converters may use different CSS support and option names; check their documentation before applying browser-specific settings.
1. Identify what is actually cut off
First decide whether content is absent, clipped at an edge, split across pages, or merely styled differently. These symptoms point to different causes:
- Text or an element is missing: check print rules such as
display: none, conditional visibility, or content that JavaScript has not rendered yet. - Content ends at a straight boundary: inspect fixed dimensions,
overflow: hiddenorclip, and positioned elements. - A table, card, or figure splits between pages: adjust break rules selectively; splitting may be valid when the block cannot fit on one page.
- The whole page is unexpectedly scaled or has the wrong margins: compare API paper settings with
@page. - Text appears but background colors or images are missing: check the renderer’s background-print option.
Record the renderer and version, the input URL or HTML, paper format and orientation, margins, and relevant PDF options. Keep a copy of the original PDF so each change can be compared against the same input.
2. Inspect the print CSS cascade
Open the page in browser print preview or emulate print media in developer tools. Compare print and screen computed styles for the affected element and its ancestors, especially display, visibility, width, height, overflow, positioning, and grid or flex layout.
Print styles are allowed to change a page’s layout and visibility. Search stylesheets for @media print, print-only stylesheets, and @page. An intentional rule that hides a navigation bar may also match content accidentally because of a broad selector. MDN documents [print media styles and the @page rule](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Media_queries/Printing).
For browser-generated PDFs, use print media unless the intended output is specifically the screen layout. Puppeteer and Playwright both document print CSS as the default for their PDF methods. Switching to screen media can help diagnose a print stylesheet problem, but it does not replace making the print layout fit the page.
3. Align paper size, orientation, and margins
Choose one intended page geometry and make the CSS and renderer agree. CSS @page can specify dimensions, orientation, and margins. Playwright’s preferCSSPageSize controls whether CSS page size takes priority over API paper dimensions; its documented default is false, which scales content to fit the API paper size. See the [Playwright PDF options](https://playwright.dev/docs/api/class-page#page-pdf).
/* Put print-specific layout rules in your stylesheet. */
@media print {
@page {
size: A4 portrait;
margin: 12mm;
}
html,
body {
/* Avoid fixed screen heights that constrain a long document. */
height: auto;
}
.screen-only {
display: none !important;
}
.keep-together {
break-inside: avoid;
}
.start-new-page {
break-before: page;
}
}
Use the paper format and margins that match the document’s intended reading or printing context. If the renderer sets margins while CSS also sets them, the effective printable area may differ from what you expect. Check whether your selected renderer option overrides CSS or scales the result to fit.
4. Find constraints that clip content
Inspect the affected element and every ancestor between it and the page. Common suspects include fixed height or max-height, fixed widths wider than the printable area, overflow: hidden or overflow: clip, nested scroll containers, absolutely positioned content, and screen-specific viewport assumptions. These are diagnostic possibilities, not a universal cause.
For example, a dashboard panel designed to scroll on screen may hide everything after its visible height when printed. Override only the relevant component in print CSS:
@media print {
.report-panel {
height: auto !important;
max-height: none !important;
overflow: visible !important;
}
.report-layout {
position: static;
width: auto;
}
}
Avoid global overrides until you know which element is responsible. Changing every ancestor’s positioning or overflow can create new pagination problems.
5. Control page breaks without trapping oversized content
Use break-inside: avoid for compact items that should remain together, such as a short card, figure and caption, or table row. Use break-before: page or break-after: page when a section should start or end on a deliberate page boundary. MDN explains [break properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/break-inside) and the legacy page-break-inside alias.
@media print {
figure,
.summary-card,
tr {
break-inside: avoid;
}
.chapter {
break-before: page;
}
.appendix {
break-after: page;
}
}
Do not apply “keep together” to long content that is taller than the printable page. The renderer cannot make an oversized block fit simply by avoiding a break; it may still split it or produce awkward whitespace. Large tables should generally be allowed to continue across pages, with suitable repeated headers if supported by your markup and renderer.
6. Wait for fonts and assets, and check backgrounds
A page captured before its content is ready can look incomplete even when the PDF layout rules are sound. Make sure client-rendered data has appeared, images have loaded, and web fonts are available before generating the PDF. Puppeteer’s PDF generation documentation says Page.pdf() waits for fonts by default; that does not ensure your application data or every remote image has finished loading. See [Puppeteer PDF generation](https://pptr.dev/guides/pdf-generation).
Background printing is a separate option. Playwright’s printBackground defaults to false; enable it when background graphics are part of the intended document. Puppeteer may modify colors for printing; its docs describe -webkit-print-color-adjust for preserving exact colors. Background differences can make sections appear missing when text is still present.
7. Generate a PDF with Puppeteer
This Node.js example loads a page, waits for navigation and fonts, then writes a PDF using the document’s CSS page size where available. Install Puppeteer in a project first with npm install puppeteer. Puppeteer’s PDF API uses print media by default; call emulateMediaType('screen') only when screen styling is the actual desired output.
// save as make-pdf.mjs; run with: node make-pdf.mjs
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', {
waitUntil: 'networkidle2',
timeout: 60000,
});
await page.evaluate(() => document.fonts.ready);
await page.pdf({
path: 'output.pdf',
printBackground: true,
preferCSSPageSize: true,
margin: { top: '12mm', right: '12mm', bottom: '12mm', left: '12mm' },
});
} finally {
await browser.close();
}
networkidle2 is a navigation wait condition, not proof that application-specific rendering is complete. For a client-rendered report, wait for a meaningful selector before calling pdf(), and set a timeout appropriate to the application:
await page.waitForSelector('[data-report-ready="true"]', { timeout: 30000 });
await page.evaluate(() => document.fonts.ready);
await page.pdf({ path: 'output.pdf', printBackground: true });
Puppeteer’s Page.pdf() accepts PDF options; consult the [current API reference](https://pptr.dev/api/puppeteer.pdfoptions) for options and defaults supported by your installed version.
8. Generate a PDF with Playwright
This JavaScript example uses Playwright’s Chromium browser. Install with npm install playwright; install its browser binaries as required by the project setup. The explicit paper format and margins below are appropriate when the API settings should define the page size. Set preferCSSPageSize: true when the CSS @page size should take priority.
// save as make-pdf.mjs; run with: node make-pdf.mjs
import { chromium } from 'playwright';
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', {
waitUntil: 'networkidle',
timeout: 60000,
});
await page.waitForSelector('[data-report-ready="true"]', { timeout: 30000 });
await page.evaluate(() => document.fonts.ready);
await page.pdf({
path: 'output.pdf',
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
margin: { top: '12mm', right: '12mm', bottom: '12mm', left: '12mm' },
});
} finally {
await browser.close();
}
Playwright’s PDF options include paper format or width and height, orientation, margins, page ranges, scale, headers and footers, background printing, and CSS page-size preference. Choose the options relevant to the document and verify defaults against the [Playwright API reference](https://playwright.dev/docs/api/class-page#page-pdf), since APIs can change between versions.
9. Validate one change at a time
- Reproduce the PDF with the same renderer, version, input, and options.
- Inspect print media and the element at the clipping boundary.
- Change one cause: a print rule, a dimension or overflow constraint, page size or margins, break behavior, or asset readiness.
- Regenerate the PDF and compare the same page boundary and content.
- Keep the fix only if it resolves the defect without creating a new one on other pages or viewport sizes.
Browser print preview is useful for narrowing down CSS issues, but validate the actual PDF created by the production renderer and settings. A different browser, version, font environment, or paper configuration can change pagination.
10. Troubleshooting common symptoms
| Symptom | Likely cause to inspect | Next step |
|---|---|---|
| PDF differs sharply from the visible page | Print CSS is active by default | Inspect @media print; emulate screen media only if screen styling is the requirement. |
| Right edge or columns are missing | Content exceeds printable width, or a container clips overflow | Compare content width with paper width minus margins; inspect ancestor widths and overflow. |
| Bottom of a panel or report is missing | Fixed height, max-height, or a scroll container | Set an appropriate print height and overflow for the affected component. |
| Rows or cards split awkwardly | No suitable break rule, or a block is too tall to keep together | Apply break-inside: avoid to compact units; allow oversized content to paginate. |
| Pages are unexpectedly scaled | CSS @page and API paper size disagree |
Choose which setting controls size; in Playwright check preferCSSPageSize. |
| Colors or background panels are absent | Background graphics are not printed, or print color adjustment changes them | Enable the renderer’s background option and review print color CSS. |
| Some images or glyphs are missing | Assets or fonts were unavailable when PDF generation began | Wait for the relevant content and fonts; verify resource loading and network access. |
| Only some pages are blank or incomplete | Conditional print styles, page ranges, or content readiness varies by page | Check page-range options, per-page CSS, and the rendered DOM before generating. |
| A CSS fix works in one converter but not another | Different renderer capabilities or versions | Check that converter’s documentation and reproduce using its actual runtime. |
11. Performance, reliability, and cost
PDF work consumes browser time and memory, especially for long pages, high-resolution imagery, and pages with many remote assets. Set navigation and selector timeouts, close browser pages and processes reliably, and avoid waiting indefinitely for a network-idle state on pages with persistent connections. For repeatable output, control the renderer version, fonts, paper settings, and input content.
The dossier does not establish performance benchmarks or pricing for self-managed Puppeteer and Playwright, nor for other converters. For a self-managed browser, account for the infrastructure and maintenance needed to run the browser and load the page’s assets. For a hosted API, verify its current pricing, output controls, and failure handling directly before choosing it.
12. Or skip the browser setup
If your goal is a PDF of a live URL and you do not want to manage browser setup, [ScreenshotNeo](https://screenshotneo.com) can return a PDF through its screenshot API. Its PDF options include paper size, margins, landscape orientation, and page ranges. See the [ScreenshotNeo API documentation](https://screenshotneo.com/docs/) for request options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-d format=pdf \
-o page.pdf
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://stripe.com",
"format": "pdf",
},
timeout=90,
)
r.raise_for_status()
with open("page.pdf", "wb") as f:
f.write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com',
format: 'pdf',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: ${res.status}`);
await Bun.write('page.pdf', res);
Cookie banners, newsletter popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. [Create a free ScreenshotNeo account](https://screenshotneo.com/account/sign-up/).
13. Frequently asked questions
Should I switch the PDF renderer to screen media?
Only when the document is meant to match its screen styling. Print media is the documented default for Puppeteer and Playwright PDF generation; print CSS is usually the right place to make a printable document fit.
Does break-inside: avoid guarantee a table row stays on one page?
No. It influences pagination but cannot make content fit when it is taller than the available page area. Test the target renderer with the real content.
Why does my browser preview look right but the generated PDF does not?
Confirm that preview and generation use the same browser engine, paper size, margins, print settings, and CSS. Also check that the production page has finished loading its data and assets.
Can one CSS fix work in every HTML-to-PDF converter?
Not necessarily. Renderer support and options vary. Reproduce with the actual converter and check its current documentation before relying on a browser-specific setting.
References
- Puppeteer: Page.pdf() and PDF generation guide.
- Playwright: Page.pdf().
- MDN: Printing,
@page, andbreak-inside.


