Use PDF units for margins, reserve the printable area before scaling the canvas, and repeat the same offsets on every page. With html2pdf.js, pass a margin array in the jsPDF unit (millimetres by default in the example below). With html2canvas and jsPDF directly, calculate the available width and height yourself, then place the rasterized canvas at (left, top) on each page. The latter approach fixes the common problem where the first page has margins but later pages do not.
Choose the margin workflow
There are two reliable implementations. Pick the wrapper when you want quick setup and built-in page-break handling; use direct html2canvas plus jsPDF when you need exact coordinates, custom pagination, or diagnostics.
| Approach | Margin setup | Page-break control | Output characteristics |
|---|---|---|---|
| html2pdf.js | margin: 15, [vertical, horizontal], or [top, left, bottom, right] |
pagebreak modes such as css, legacy, and avoid-all |
Image-based PDF; text may not be selectable and files can be larger |
| html2canvas + jsPDF | Subtract left/right margins from page width and top/bottom from page height | You control offsets or render separate page sections | Maximum placement control; the captured DOM is still rasterized |
Both workflows convert CSS pixels to a PDF coordinate system such as mm, pt, or in. A canvas width in pixels cannot be used as a jsPDF width without an aspect-ratio conversion.
Fast solution with html2pdf.js
Install and capture an element
Load html2pdf.js and select the element you want to export. Its documented pipeline is .from() → .toContainer() → .toCanvas() → .toImg() → .toPdf() → .save().
#1 Best Overall
- Scanner type: Document
- Connectivity technology: USB
- With Auto Scan Mode, the scanner automatically detects what you're scanning
- Digitize documents and images
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<script>
const element = document.querySelector('#report');
const options = {
margin: [15, 12, 15, 12], // top, left, bottom, right (jsPDF units)
filename: 'report.pdf',
image: { type: 'jpeg', quality: 0.95 },
html2canvas: {
scale: window.devicePixelRatio,
useCORS: true,
scrollX: 0,
scrollY: 0
},
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: ['css', 'legacy'] }
};
html2pdf().set(options).from(element).save();
</script>
The scalar form margin: 15 applies 15 units to all sides. The two-value form [vertical, horizontal] applies the first value to top and bottom and the second to left and right. The four-value form is ordered [top, left, bottom, right]. Keep the margin values in the same unit configured in jsPDF.
Control breaks explicitly
Add CSS such as break-before: page, break-after: page, or break-inside: avoid to page-sized sections, and retain the css page-break mode. avoid-all can prevent splitting more elements, but may create unexpectedly large blank areas when an element is taller than the usable page.
Exact margins with html2canvas and jsPDF
Complete multi-page example
This pattern treats the canvas as one tall image. It reserves both horizontal and vertical margins, preserves the image aspect ratio, and uses the same left offset on every page.
async function exportPdf(element) {
const canvas = await html2canvas(element, {
scale: window.devicePixelRatio,
useCORS: true,
scrollX: 0,
scrollY: 0
});
const pdf = new jsPDF({
unit: 'mm',
format: 'a4',
orientation: 'portrait'
});
const margin = { top: 15, right: 15, bottom: 15, left: 15 };
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const contentWidth = pageWidth - margin.left - margin.right;
const contentHeight = canvas.height * contentWidth / canvas.width;
const usableHeight = pageHeight - margin.top - margin.bottom;
if (contentWidth <= 0 || usableHeight <= 0) {
throw new Error('Margins leave no printable area');
}
const image = canvas.toDataURL('image/png');
let offset = 0;
while (offset < contentHeight) {
if (offset > 0) pdf.addPage();
pdf.addImage(
image,
'PNG',
margin.left,
margin.top - offset,
contentWidth,
contentHeight
);
offset += usableHeight;
}
pdf.save('export.pdf');
}
exportPdf(document.querySelector('#report'));
On page one, the image begins at margin.top. On subsequent pages, the negative vertical offset moves the same tall image upward by one usable-page height, while margin.left remains unchanged. The bottom margin is enforced because the loop advances by pageHeight - top - bottom, not by the full page height.
Recommended Free Tools
How the calculation works
- Read
pageWidthandpageHeightfrompdf.internal.pageSize; do not hard-code A4 dimensions if users can choose another format or orientation. - Subtract the left and right margins:
contentWidth = pageWidth - left - right. - Scale the canvas proportionally:
contentHeight = canvas.height × contentWidth / canvas.width. - Reserve vertical margins:
usableHeight = pageHeight - top - bottom. - Place each page at
x = leftandy = top - offset, then incrementoffsetbyusableHeight.
Never stretch the image by calculating width and height independently. Doing so distorts text and graphics and can make the apparent margins differ between pages.
Rank #2
- FAST DOCUMENT SCANNING — Document scanner with feeder allows you to speed through stacks with a 50-sheet Auto Document Feeder (ADF); Efficient office scanner to help you scan more productively
- INTUITIVE, HIGH-SPEED SOFTWARE — Quickly scan with this desktop document scanner; Epson ScanSmart Software lets you easily preview scans, email files, upload to the cloud, and more; Plus, automatic file naming saves even more time
- SEAMLESS INTEGRATION — Easily incorporate your data into most document management software with the included TWAIN driver; Office document scanner integrates seamlessly with business workflows
- EASY SHARING — Duplex scanner allows you to scan straight to email or popular cloud storage2 services like Dropbox, Evernote, Google Drive, and OneDrive for simple storage and sharing
- SIMPLE FILE MANAGEMENT — Scanner allows the creation of searchable PDFs with Optical Character Recognition (OCR) and convert scans to editable Word or Excel files effortlessly; Designed for home and office document scanning
When a tall-image loop is the wrong model
The negative-offset loop is convenient, but it can cut a paragraph, table row, or card at an arbitrary point. For reports where page semantics matter, create separate page-sized DOM sections and render each section independently, or use html2pdf.js break controls.
Render explicit sections
Give each section a known page role (for example, .pdf-page), render it to a canvas, and add one image per jsPDF page. Each section then starts at the top margin and cannot inherit a partial offset from the previous section. You must still ensure the section’s rendered height fits inside usableHeight.
Keep content inside the usable box
- Set a page container width that matches
contentWidthafter CSS-to-PDF scaling. - Avoid fixed-height elements taller than the usable page unless they are intentionally allowed to span pages.
- Use
break-inside: avoidfor headings and small cards, but test large tables because avoiding a break may push a whole table to the next page.
Sharpness, CSS differences, and cross-origin content
Increase raster resolution without changing geometry
scale controls the canvas pixel density. A higher scale can make small type and lines sharper, but it does not change PDF page size or margin math. It also increases memory use, encoding time, and file size. Start with window.devicePixelRatio; raise it only after checking output size and browser limits.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Expect DOM reconstruction differences
html2canvas reconstructs a DOM representation rather than taking a compositor-level screenshot. Unsupported or browser-specific CSS can therefore differ from what the user sees. Test fonts, gradients, filters, pseudo-elements, sticky positioning, and complex transforms in the target browsers.
Handle images and iframes
Cross-origin images require appropriate CORS headers or a proxy. A missing CORS permission can make an image unavailable or taint the canvas, causing toDataURL() to fail. Same-origin content is the best diagnostic baseline; add external images, fonts, iframes, and complex CSS one category at a time.
Debug margins systematically
- Confirm the jsPDF unit and every margin value use the same unit (
mm,pt, orin). - Log
pageWidth,pageHeight,contentWidth,contentHeight, andusableHeight. - Verify
contentWidth > 0and that the aspect-ratio calculation uses the original canvas dimensions. - Set
scrollX: 0andscrollY: 0if a scrolled viewport produces a shifted capture origin. - Capture a plain, same-origin block. If that works, reintroduce external images, fonts, iframes, and advanced CSS until the failing feature is identified.
- For break-sensitive documents, replace the tall-image loop with explicit sections or html2pdf.js page-break selectors.
Typical symptoms and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Margins vanish after page one | Offset advances by full page height or later pages use x = 0 |
Advance by pageHeight - top - bottom and always place at x = left. |
| Content is stretched | Width and height were scaled independently | Derive height from canvas.height * contentWidth / canvas.width. |
| Right edge is clipped | Margins were not subtracted before sizing | Calculate contentWidth from both horizontal margins. |
| Blank or missing images | CORS or iframe restrictions | Use same-origin assets, enable CORS on the asset server, or configure a proxy. |
| Unexpected blank areas | Overly aggressive avoid-all or oversized unbreakable element |
Use targeted break rules and split content that exceeds the usable height. |
| Blurry PDF | Low canvas scale or extreme downsampling | Increase scale gradually and balance sharpness against memory and file size. |
Performance and reliability considerations
- Very tall pages create large canvases. Capture separate sections when documents approach browser memory limits.
- JPEG usually produces smaller files for photographic content; PNG preserves text-like edges and transparency but can be larger.
- Wait for fonts and images to finish loading before calling
html2canvas; otherwise the canvas may contain fallback fonts or empty boxes. - Use deterministic viewport dimensions and disable animated content during capture to avoid layout shifts.
- Test portrait and landscape separately because page dimensions, usable height, and page count change with orientation.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server when you need a rendered page without maintaining a headless-browser pipeline. It accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
For a PDF or image request, use one GET call (see the ScreenshotNeo documentation):
Rank #3
- SET IT UP ONCE AND PRINT WITH CONFIDENCE. No complicated maintenance. Just easy, reliable printing you can count on.
- INK FOR YEARS. NOT MONTHS. Up to 2 years of ink included. Get thousands of pages of cartridge-free printing. More pages, less hassle
- KEEPS PRINTING WELL AFTER COMPETITORS HAVE QUIT. No complex maintenance. Sharper text, richer colors.[2] Only with HP Smart Tank
- INNOVATION YOU CAN TRUST. Cartridge-free printing that keeps you printing longer with fewer interruptions, powered by the trusted HP innovation you rely on today
- PREMIUM SUPPORT - Strong technical expertise to solve issues faster.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const body = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', body));
It also supports full-page captures with lazy images, CSS-selector element captures, dark mode, device presets and custom viewports, retina scale, PDF paper size/margins/orientation/page ranges, custom CSS and JavaScript, clicks, selector waits, delays, network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account to try it.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.FAQ
Can I use centimetres or inches for margins?
Yes. Configure jsPDF with the matching unit and express every margin in that unit. Do not mix millimetres, points, inches, and CSS pixels in one calculation.
Why is selectable text missing?
html2canvas turns the DOM into a bitmap, and jsPDF places that bitmap as an image. A raster workflow does not preserve the original text layer.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Should I use PNG or JPEG?
PNG is generally safer for text, line art, and transparency. JPEG can reduce size for photographic pages, at the cost of compression artifacts around fine text.
Rank #4
- FAST SPEEDS - Scans color and black and white documents a blazing speed up to 16ppm (1). Color scanning won’t slow you down as the color scan speed is the same as the black and white scan speed.
- ULTRA COMPACT – At less than 1 foot in length and only about 1. 5lbs in weight you can fit this device virtually anywhere (a bag, a purse, even a pocket).
- READY WHENEVER YOU ARE – The DS-640 mobile scanner is powered via an included micro USB 3. 0 cable allowing you to use it even where there is no outlet available. Plug it into you PC or laptop and you are ready to scan.
- WORKS YOUR WAY – Use the Brother free iPrint&Scan desktop app for scanning to multiple “Scan-to” destinations like PC, Network, cloud services, Email and OCR. (2) Supports Windows, Mac and Linux and TWAIN/WIA for PC/ICA for Mac/SANE drivers. (3)
- OPTIMIZE IMAGES AND TEXT – Automatic color detection/adjustment, image rotation (PC only), bleed through prevention/background removal, text enhancement, color drop to enhance scans. Software suite includes document management and OCR software. (4)
How do I support landscape pages?
Create jsPDF with orientation: 'landscape', then read its page dimensions and run the same margin subtraction and aspect-ratio calculations.
Frequently Asked Questions
Can I use centimetres or inches for margins?
Yes. Configure jsPDF with the matching unit and express every margin in that unit; never mix PDF units with CSS pixels.
Why is selectable text missing?
html2canvas rasterizes the DOM, so jsPDF receives an image rather than a text layer.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesShould I use PNG or JPEG?
PNG suits text, line art, and transparency; JPEG is smaller for photographic pages but may show compression artifacts.
How do I support landscape pages?
Set jsPDF orientation to landscape, then read its page dimensions and repeat the same margin calculations.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

