ScreenshotNeo

BlogComparisons

Best HTML to PDF Converters That Preserve CSS Variables

Compare HTML to PDF converters with documented CSS variable support, then verify your own styles, pagination, and renderer configuration.

By the ScreenshotNeo team4 October 20267 min read

Short answer: Based on the official documentation in this comparison, WeasyPrint 70.0 is the clearest documented choice: its stable API reference explicitly confirms support for CSS custom properties and var(). DocRaptor is also a documented option when configured to use its Prince 13 Pipeline 8; DocRaptor said that existing documents were not upgraded automatically, so verify the pipeline used by your account. Neither statement guarantees that every browser-oriented stylesheet will render identically in PDF.

This guide compares the documented evidence, shows how to check a stylesheet’s variables, and gives a practical way to qualify a converter against your actual template. It is not a cross-engine benchmark or a claim that every converter has been exhaustively tested.

What it means to preserve CSS variables

CSS custom properties are usually declared with names such as --brand-color and referenced with var(--brand-color). They follow the CSS cascade and can inherit. A var() fallback can provide a value when a variable is missing or invalid, provided the rendering implementation supports custom properties. A fallback does not make an implementation that lacks custom-property support understand the feature. See MDN’s var() reference.

:root {
  --brand-color: #2457c5;
  --body-color: #202124;
}

.report {
  color: var(--body-color, #202124);
}

.report h1 {
  color: var(--brand-color, #2457c5);
}

A useful compatibility check must cover more than whether one declaration renders. Test the scopes and inheritance patterns your template uses, linked stylesheets and fonts, print-specific rules, page breaks, and the other layout features in the document.

Converters with documented CSS variable support

Converter What the cited official material confirms What to verify
WeasyPrint 70.0 Its current stable API reference explicitly says custom properties and var() notation are supported. Check the current feature reference for other CSS your document needs, then render representative pages and inspect the result.
DocRaptor with Prince 13 / Pipeline 8 DocRaptor’s release note dated 2020-10-21 says Prince 13 added custom-property support in Pipeline 8. Establish which pipeline your account and request use. The release note says existing documents were not upgraded automatically and users needed to test and upgrade.
Prince The official Prince user guide describes converting HTML/XML to PDF using CSS. The inspected guide is for Prince 15, but the reviewed excerpt does not establish which version introduced custom-property support. For the Prince 13 claim, rely on DocRaptor’s Pipeline 8 release note.
PDFreactor 12.7.1 The reviewed manual documents HTML5 parsing, HTML+CSS rendering, and CSS validation/support-query configuration. The inspected material does not explicitly confirm custom-property support. Check the relevant current support entry or run your own representative test before choosing it for this requirement.

Sources: WeasyPrint stable API reference, DocRaptor’s Prince 13 / Pipeline 8 release note, Prince 15 user guide, and PDFreactor manual. The WeasyPrint reference also describes limits in areas separate from custom properties, including right-to-left/bidirectional text and aspects of flexbox and grid. A positive result for variables does not establish support for those features.

How to choose and qualify a converter

  1. Start with the documented requirement. If CSS custom properties are essential, WeasyPrint 70.0 has the most direct confirmation among the reviewed sources. Treat DocRaptor as a candidate only after confirming the Prince 13 Pipeline 8 configuration.
  2. Inventory your real template. Record variable declarations, where they are scoped, fallback values, linked CSS, fonts, print media rules, pagination, and layout features such as grid or flexbox. Note whether the page depends on JavaScript to populate content.
  3. Pin and record the renderer configuration. Capture the engine version and, for DocRaptor, the pipeline selection alongside your deployment configuration. Recheck after upgrades or configuration changes.
  4. Render a representative fixture. Use a document that exercises inherited and locally scoped variables, a missing-variable fallback, long content, page breaks, fonts, and the print rules used in production. Compare the PDF visually and check extracted text where text output matters.
  5. Check failure behavior and operations. Determine how the chosen integration handles unavailable assets, timeouts, JavaScript, sensitive HTML, concurrency, and retries. Confirm current deployment requirements, support terms, and pricing directly with the vendor; the reviewed source set does not establish a current pricing or performance comparison.

These qualification steps are practical guidance inferred from the documented CSS behavior and product scope; this research pass did not run independent rendering tests.

Runnable CSS variable test fixture

Save the following as variables-test.html and open or submit it using the converter and integration you are evaluating. It includes a root variable, an inherited variable, a local override, a fallback, and print styling. The fixture itself is converter-neutral; the exact command or API call depends on your selected product and deployment.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>CSS custom property PDF check</title>
  <style>
    :root {
      --brand: #2457c5;
      --ink: #202124;
      --paper: #ffffff;
    }
    body {
      color: var(--ink, #202124);
      background: var(--paper, white);
      font: 16px/1.5 sans-serif;
      margin: 2rem;
    }
    h1 { color: var(--brand, #2457c5); }
    .scope { --brand: #a12666; }
    .scope h2 { color: var(--brand); }
    .fallback { color: var(--not-defined, #147a42); }
    @media print {
      h1 { break-after: avoid; }
      .page-two { break-before: page; }
    }
  </style>
</head>
<body>
  <h1>Root variable should be blue</h1>
  <section class="scope">
    <h2>Inherited local override should be magenta</h2>
  </section>
  <p class="fallback">Missing variable should use the green fallback</p>
  <section class="page-two">
    <h2>Print page break check</h2>
    <p>Add enough representative content here to exercise real pagination.</p>
  </section>
</body>
</html>

Check that the root and overridden colors differ as expected, the absent variable uses its fallback, text and fonts load, and the print page break behaves properly. Also test your actual production stylesheets: a small fixture is a diagnostic, not a substitute for validating the complete document.

Why CSS variables can disappear or render incorrectly

  • The engine or selected pipeline lacks support. Confirm the exact renderer version and configuration, then verify against its current documentation or the fixture above.
  • The variable is out of scope. A custom property inherits through the element tree; a declaration in a sibling or unrelated scope is not available. Move it to an applicable ancestor or define it where it is needed.
  • The referenced name is misspelled or undefined. Check that declaration and reference names match, including the leading --. Supply a fallback where appropriate.
  • A value is invalid in context. A variable can resolve to tokens that are not valid for the consuming property. Check the resolved value and provide a suitable fallback.
  • The PDF differs beyond variable colors. Variables can work while another layout feature, print rule, font, or asset behaves differently. Check the converter’s feature documentation and isolate the issue with a minimal fixture.
  • The hosted service uses a different engine setting than expected. For DocRaptor, verify the active pipeline; the Pipeline 8 release note specifically warned that existing documents were not upgraded automatically.

Performance, reliability, and cost considerations

The reviewed evidence establishes CSS compatibility details, not comparative speed, uptime, throughput, service-level commitments, or current converter prices. Choose using your own document size and operating constraints rather than assuming that variable support predicts rendering speed or reliability.

  • Performance: benchmark representative documents in your deployment environment, including external assets, fonts, JavaScript if required, and multi-page output. Measure end-to-end latency and resource use under expected concurrency.
  • Reliability: decide how to handle timeouts, missing assets, retries, and partial or invalid output. Avoid retrying deterministic template errors indefinitely; log the renderer version and configuration with each failure.
  • Cost: compare current vendor pricing and the operational cost of running a renderer yourself. Include compute, maintenance, support, and any usage-based charges that apply to your setup. No current pricing comparison was verified in this research.
  • Change control: rerun your fixture and representative documents when upgrading a renderer, changing a DocRaptor pipeline, or editing shared CSS.

Or skip the browser setup

If a PDF is not required and a screenshot of the rendered page will do, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. For PDF output, consult the ScreenshotNeo API documentation for the PDF parameters.

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)
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}`);
  • Cookie banners are accepted and removed before capture; more than 60 known consent platforms, newsletter popups, and chat widgets can be removed, with each step configurable.
  • Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses include X-Page-Verdict and X-Billed headers.
  • An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
  • The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots. Every feature is on every plan.

Sign up for ScreenshotNeo’s free plan: 1,000 screenshots a month, no card required.

FAQ

Does a fallback make CSS variables work in an unsupported converter?

No. The fallback handles a missing or invalid variable in an implementation that supports custom properties; it does not add support to an implementation that lacks the feature.

Does WeasyPrint support every CSS feature used by browsers?

No. Its documentation confirms custom properties and var(), while also documenting limitations in other CSS areas. Check the current feature reference for the rest of your stylesheet.

Can I assume DocRaptor uses Prince 13 Pipeline 8?

No. Verify the pipeline configured for your account or request. DocRaptor’s 2020 release note said existing documents required testing and an upgrade.

Does this comparison prove which converter is fastest?

No. The reviewed sources do not provide a controlled speed comparison. Benchmark your own documents and deployment setup.