Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
For pixel-faithful output, capture the element with a real browser rather than assuming a DOM-to-canvas library reproduces every CSS property. html2canvas rebuilds an image from DOM and computed-style information; it does not take a native screenshot of the browser’s pixels. Use it when its supported feature set fits your design. For complex CSS, server-side work, or a result that must match what users see, drive a real browser (such as Puppeteer or Playwright) and validate the exact browser, viewport, fonts, assets and timing.
Choose the rendering method before changing CSS
The conversion tool determines what “preserve” means. A DOM reconstruction paints only the properties its renderer implements. A browser screenshot captures the pixels produced by a browser engine, including layout, fonts, compositing and effects that the engine supports.
| Question | DOM reconstruction with html2canvas | Real-browser screenshot |
|---|---|---|
| What is rendered? | A canvas representation rebuilt from DOM and style data. | The browser’s rendered pixels, captured through automation. |
| CSS fidelity | Limited to properties implemented by the library; full CSS support is not possible. | Uses a browser engine, but you still need to verify browser version, fonts, assets and timing. |
| Where it runs | In a browser, using window, document and computed styles. |
On a client or server where an automation tool can launch or control a browser. |
| Cross-origin resources | Canvas security rules apply; CORS or a proxy may be required. | The page still follows browser network and security rules, which must be configured in your environment. |
| Useful controls | Clone callback, viewport dimensions, background and resource options. | Browser viewport, readiness waits and screenshot settings. |
Preserve styles with html2canvas
Install and capture a stable element
Run html2canvas in the browser. It cannot run directly in Node.js because Node does not provide the browser APIs it requires.
import html2canvas from 'html2canvas';
const element = document.querySelector('#invoice');
if (!element) throw new Error('Missing #invoice');
await document.fonts?.ready;
await Promise.all(Array.from(document.images).map(img => img.complete
? Promise.resolve()
: new Promise(resolve => {
img.addEventListener('load', resolve, { once: true });
img.addEventListener('error', resolve, { once: true });
})));
const canvas = await html2canvas(element, {
windowWidth: document.documentElement.clientWidth,
windowHeight: document.documentElement.clientHeight,
backgroundColor: '#ffffff',
scale: window.devicePixelRatio,
useCORS: true,
logging: true
});
const link = document.createElement('a');
link.download = 'invoice.png';
link.href = canvas.toDataURL('image/png');
link.click();
Wait for web fonts, images, data fetched by the component and layout-affecting animations before calling the renderer. Capture a stable state, not a frame halfway through a transition. A completed promise only means a canvas was produced; compare that canvas with the live element.
#1 Best Overall
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Set the viewport and output dimensions deliberately
windowWidth and windowHeight influence media queries and responsive layout. Set them to the viewport you intend to represent rather than relying on an incidental browser size. For a long element, use its scroll dimensions when appropriate:
const box = document.querySelector('#report');
const canvas = await html2canvas(box, {
windowWidth: box.scrollWidth,
windowHeight: box.scrollHeight,
width: box.scrollWidth,
height: box.scrollHeight,
backgroundColor: null,
scale: 2
});
backgroundColor: null keeps the canvas transparent. A numeric scale controls output density; higher values increase pixel dimensions and memory use. Confirm the final file dimensions rather than assuming CSS pixels equal image pixels.
Use onclone for export-only changes
The callback receives the cloned document used for rendering. You can remove a blinking caret, freeze an animation, or add an export class without modifying the page the user sees.
Recommended Free Tools
const canvas = await html2canvas(document.querySelector('#card'), {
onclone: (clonedDocument) => {
const style = clonedDocument.createElement('style');
style.textContent = `
*, *::before, *::after { animation: none !important; transition: none !important; }
.editing-only { display: none !important; }
`;
clonedDocument.head.appendChild(style);
}
});
foreignObjectRendering is an alternate path to test for your target browser; it is not a universal switch that adds support for every CSS feature.
Rank #2
Check CSS features instead of assuming browser parity
Every CSS property has to be implemented individually by html2canvas. A property that works in the live browser can therefore be absent, simplified or painted differently in the export. Consult the supported-features list for the exact html2canvas release you install and make a small fixture containing the properties your design depends on.
- Test gradients, shadows, filters, masks, blend modes, transforms, pseudo-elements and custom fonts separately.
- Include responsive breakpoints in the fixture and render at each production viewport.
- Compare text wrapping, line height, baseline alignment and font weight, not just the outer box.
- Record the browser, operating system, device-pixel ratio and library version used for the comparison.
If a required property is unsupported, your choices are to simplify that style for export, add a capture-only fallback in onclone, or switch to a real-browser screenshot.
Make images, fonts and other assets available
Cross-origin images
Canvas security prevents unrestricted reading of resources from another origin. Set useCORS: true only when the image server sends an appropriate Access-Control-Allow-Origin header. If you cannot change that server, route the resource through a proxy you control and configure it to return the needed CORS headers.
const canvas = await html2canvas(element, {
useCORS: true,
imageTimeout: 15000,
logging: true,
onerror: (error) => console.error('Resource error', error)
});
Inspect the browser network panel for blocked requests and response headers. allowTaint does not make a tainted canvas safe to export; a tainted canvas can remain unreadable through toDataURL() or toBlob().
Rank #3
Fonts and generated content
Wait for document.fonts.ready and ensure the font files themselves load successfully. A fallback font changes line breaks and element height even when every CSS declaration is present. Check pseudo-elements and CSS-generated content in your fixture, because a missing asset or unsupported feature can make them appear to vanish.
When a real-browser screenshot is the safer answer
Use browser automation when the image must represent the browser result, when capture is server-side, or when the page uses CSS that html2canvas does not implement. The html2canvas FAQ points to Puppeteer and Playwright for server-side screenshots. In either tool, set an explicit viewport, wait for the page’s readiness condition, wait for fonts and images, disable or finish animations, and capture the intended element or page.
Browser capture does not remove the need for verification. Different browser versions can rasterize text and effects differently; external requests can fail; and a page that is visually complete for a person may still be changing when automation takes the shot.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Prevent blank, clipped or oversized exports
Canvas limits
Maximum canvas dimensions vary by browser, operating system, GPU and device. A page that works on one machine can become blank or partially rendered on another. Test the largest real target, reduce the scale, split a long page into tiles, or capture smaller sections when memory or dimension limits are reached. Do not treat one fixed maximum as universal.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Viewport and clipping
If only the visible portion appears, check the element’s scroll dimensions and the capture width and height. If a responsive breakpoint is wrong, inspect windowWidth and windowHeight. If content is missing at the bottom, wait for lazy-loaded content and verify that the component has finished expanding before capture.
Troubleshooting checklist
| Symptom | Likely cause | Fix |
|---|---|---|
| CSS effect is missing or simplified | The property is not implemented by the html2canvas release. | Check the supported-features list; add an export fallback or use a browser screenshot. |
| Images are absent | Image loading failed, the URL is cross-origin, or CORS headers are missing. | Wait for image completion, inspect network errors, enable useCORS with server headers, or use a proxy. |
toDataURL throws a security error |
The canvas was tainted by a cross-origin resource. | Fix the resource’s CORS response or proxy it; allowTaint does not solve export access. |
| Text wraps differently | Fonts were not ready, viewport differs, or a fallback font loaded. | Await document.fonts.ready, set dimensions explicitly and verify font requests. |
| Output is cut off | Capture dimensions describe the viewport rather than the element’s full scroll area. | Use the element’s scroll dimensions and test long-content cases. |
| Output is blank or partly blank | Canvas dimensions exceed a target environment’s limit, or content was captured before loading. | Reduce scale, tile the capture, wait for readiness and test on the actual deployment devices. |
| Export contains a transient frame | Animation or transition was active. | Freeze animation in onclone or wait for a known stable state. |
Validate fidelity as a repeatable test
- Build a fixture containing the exact backgrounds, fonts, images, transforms and effects used in production.
- Render it at every supported viewport and device-pixel ratio.
- Capture the live browser view and the exported image under the same conditions.
- Compare text wrapping, edges, transparent areas, colors and asset placement at 100% zoom.
- Repeat after updating html2canvas, browser versions, fonts or CSS tooling.
Keep failed fixtures in your test suite. They reveal regressions earlier than visual inspection of a single marketing page.
Or skip the browser setup
ScreenshotNeo uses a real browser to return a PNG, JPEG, WebP or PDF from one request. It is useful when you want rendered pixels without maintaining browser automation. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteIts API supports full-page captures with lazy images, CSS-selector element captures, dark mode, 12 device presets or custom viewports, retina scale, PDF paper and page options, custom CSS and JavaScript, clicks, selector or network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous webhooks, bulk capture for up to 100 URLs per call, usage data and an OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration. An MCP server provides take_screenshot, get_page_info and capture_pdf tools to Claude, Cursor and other MCP clients.
See the ScreenshotNeo documentation for authentication and options. A minimal request is:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The Free plan includes 1,000 shots each month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account to try the capture without installing a browser.
Frequently Asked Questions
Can html2canvas preserve every CSS property?
No. Its renderer implements properties individually, so complete CSS support is not possible. Verify the features used by your installed release.
Free tools Windows power users keep installed
One-click scans. No signup required.
Why does html2canvas need a browser?
It reads browser APIs such as window, document and computed styles. For server-side work, use browser automation or a screenshot service.
Does allowTaint fix missing cross-origin images?
No. It does not bypass content policy or make a tainted canvas readable. Configure CORS headers or use a proxy.
Should I use foreignObjectRendering for all captures?
No. Treat it as an alternate option to test for your browser and design, not as a universal CSS-support switch.
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.

