Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The correct way to load a CSS string depends on the PDF renderer. In tc-lib-pdf, call setGlobalCSS($css) to replace the global stylesheet or addGlobalCSS($css) to append one. In mPDF, pass the string to WriteHTML() with HEADER_CSS, then pass the document with HTML_BODY. In dompdf, concatenate a <style> element into the HTML string supplied to loadHtml(). These engines do not implement all browser CSS, so verify the API for your installed version and inspect the generated PDF.

Choose the method for your PDF library

Renderer How to pass a CSS string Best fit
tc-lib-pdf setGlobalCSS($css) replaces global CSS; addGlobalCSS($css) appends it. A reusable baseline stylesheet shared by many documents.
mPDF WriteHTML($css, MpdfHTMLParserMode::HEADER_CSS), followed by body markup in HTML_BODY mode. Keeping stylesheet text and document markup as separate inputs.
dompdf Wrap the string in <style>...</style> inside the HTML passed to loadHtml(). A self-contained HTML document assembled in PHP.

Use the method that matches your renderer rather than trying to pass a CSS string to a generic PDF function. Method names and constants can vary between releases; check the version installed in your application.

tc-lib-pdf: set or append global CSS

tc-lib-pdf exposes two explicit methods for stylesheet text. setGlobalCSS() replaces the current global stylesheet. addGlobalCSS() appends rules to the existing global stylesheet. Pass CSS declarations only; do not include surrounding <style> tags.

Replace the global stylesheet

<?php
$css = 'body { font-family: helvetica; font-size: 10pt; }';

$pdf->setGlobalCSS($css);
$pdf->addHTMLCell(
    '<h1>Invoice</h1><p>Example content</p>',
    15,
    20,
    180
);

Use this when the new string is the complete baseline for the document. Calling setGlobalCSS() discards previously configured global rules.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Append rules without discarding existing CSS

<?php
$baseCss = 'body { font-family: helvetica; font-size: 10pt; }';
$invoiceCss = '.total { font-weight: bold; }';

$pdf->setGlobalCSS($baseCss);
$pdf->addGlobalCSS($invoiceCss);
$pdf->addHTMLCell(
    '<p class="total">Amount due: $100</p>',
    15,
    20,
    180
);

Global CSS is a lower-priority author source than <style> blocks inside the document in the described cascade. A rule in an embedded block can therefore override a global baseline, while an element’s style attribute participates at the element level. This makes global methods suitable for shared defaults and embedded rules suitable for document-specific exceptions.

mPDF: parse the stylesheet and body separately

When your CSS is stored separately from the HTML, mPDF’s parser modes keep the two inputs distinct. Send the CSS with HEADER_CSS, then send the document markup with HTML_BODY.

<?php
$stylesheet = 'body { font-family: sans-serif; color: #222; }';
$html = '<h1>Example</h1><p>PDF content</p>';

$mpdf->WriteHTML(
    $stylesheet,
    MpdfHTMLParserMode::HEADER_CSS
);
$mpdf->WriteHTML(
    $html,
    MpdfHTMLParserMode::HTML_BODY
);

// Finish with the output method required by your installed mPDF version.

The default WriteHTML() mode is intended for a complete HTML page containing head, body and style definitions. Use the stylesheet mode when the CSS is a separate string. Confirm that your installed release provides the enum or constants shown above before deploying the code.

When one complete HTML string is simpler

If you already have a complete document string, including its <head> and <style> block, the default complete-page mode is appropriate. Do not send the same CSS once in HEADER_CSS and again in the document unless you intentionally want duplicate cascade sources.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

dompdf: embed the string in a style block

dompdf accepts style blocks and element style attributes, as well as external stylesheets. For CSS held in PHP, build a complete HTML string and place the CSS between <style> tags before calling loadHtml().

<?php
$css = 'body { font-family: sans-serif; color: #222; }';
$bodyHtml = '<h1>Example</h1><p>PDF content</p>';

$html = '<!doctype html><html><head><style>'
      . $css
      . '</style></head><body>'
      . $bodyHtml
      . '</body></html>';

$dompdf->loadHtml($html);
// Call render() and your chosen output method for the installed dompdf version.

Keep the style element in the document string when the stylesheet belongs only to that PDF. dompdf describes its engine as mostly CSS 2.1 compliant with selected CSS3 properties, so browser-only layout features can render differently or be ignored.

Build the CSS string safely in PHP

Use a nowdoc for a literal stylesheet

A nowdoc keeps quotes, dollar signs and backslashes from being interpreted by PHP. It is useful for a fixed template stylesheet.

<?php
$css = <<<'CSS'
@page { margin: 18mm; }
body { font-family: sans-serif; font-size: 10pt; color: #222; }
h1 { font-size: 20pt; margin-bottom: 8pt; }
.invoice-total { font-weight: bold; text-align: right; }
CSS;

Interpolate controlled values deliberately

If a value comes from configuration, build only the value that you have validated, not arbitrary user CSS. For example, allow a server-side font choice from a fixed list and insert that choice into a template. Avoid concatenating untrusted selectors, declarations or at-rules.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Understand the cascade

  • In tc-lib-pdf, setGlobalCSS() replaces the global source and addGlobalCSS() appends to it.
  • Rules inside a document’s <style> block can override the described global baseline.
  • Inline style attributes are attached to individual elements and may override less-specific stylesheet rules.
  • Specificity, source order and the renderer’s supported properties still determine the final result.

CSS features, layout differences and validation

HTML-to-PDF engines are not browser engines. A stylesheet that works in Chrome may fail when it uses unsupported selectors, flexbox behavior, grid, JavaScript-dependent layout, web fonts or browser-specific properties. dompdf’s documented support is mostly CSS 2.1 plus selected CSS3; the other renderers also have their own supported subsets.

  1. Start with a small stylesheet containing typography, spacing, colors and simple block layout.
  2. Generate a PDF with representative long and short content.
  3. Check page breaks, margins, overflow, images, tables and repeated headers.
  4. Add advanced properties one at a time and compare the output after each change.
  5. Pin and document the renderer version used by your application, because method availability and CSS behavior can change.

Do not describe a stylesheet as browser-compatible merely because it parses. The output PDF is the authority for the renderer you actually run.

Security: treat HTML and CSS as untrusted input

Rendering a string does not make it safe. mPDF’s manual warns that it is not intended to receive outside-user HTML or CSS and says applications must vet and sanitize such input beyond ordinary browser-level sanitization.

  • Keep templates and CSS under application control whenever possible.
  • Sanitize user-provided markup and remove scripts, event handlers and dangerous URLs before rendering.
  • Validate CSS values against an allowlist rather than accepting arbitrary declarations.
  • Restrict remote resources if the renderer can fetch URLs, and set resource limits appropriate to your deployment.
  • Render untrusted documents in an isolated process or worker when your threat model requires it.

These precautions protect the server; they do not guarantee that a malicious stylesheet cannot consume excessive memory or CPU.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting common failures

Styles have no effect in tc-lib-pdf

Check that the argument contains CSS without <style> tags, that you called the method before adding the HTML cell, and that you did not accidentally replace the stylesheet later with another setGlobalCSS() call. For a one-off override, place the rule in the document’s style block or on the element.

mPDF treats CSS as visible text

The stylesheet was probably sent using the default parser mode. Send it with MpdfHTMLParserMode::HEADER_CSS, then send the markup using HTML_BODY. Also verify the namespace and constants for your installed release.

dompdf prints the CSS or ignores it

Ensure the string is inside a real <style> element located in the generated HTML, and inspect the final HTML for malformed quotes or prematurely closed tags. Then check whether the property is in dompdf’s supported CSS subset.

The PDF differs from the browser

Replace unsupported or browser-specific layout with simpler block, table or page-layout rules supported by your renderer. Verify print margins and page-break behavior in the generated PDF rather than relying on a browser preview.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

User content breaks the document or creates a security risk

Stop concatenating raw user HTML or CSS. Sanitize it with a policy designed for your renderer, restrict external resources and reject values that are not required by the document template.

Performance, reliability and cost considerations

None of the documented APIs establishes a cross-library speed or CSS-compatibility benchmark. Performance depends on document size, images, fonts, external resources and the renderer version. Keep CSS reusable and modest, avoid repeated huge strings, cache trusted templates, and set timeouts or worker limits around rendering jobs. Test the largest realistic document, not only a short sample.

When a layout is business-critical, keep a regression set of PDFs or rendered pages and compare it after library upgrades. This catches pagination and font changes that a successful PHP call alone will not reveal.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your actual goal is to capture a rendered web page rather than assemble a PDF inside PHP, ScreenshotNeo provides a website screenshot API and MCP server. It accepts a URL and returns a PNG, JPEG, WebP or PDF. Before capture it can accept consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A single request is enough for a URL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. The response identifies page status and billing with X-Page-Verdict and X-Billed headers. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed; only clean shots are billed.

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}`);

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. It includes 1,000 screenshots per month free without a card; paid plans start at $5 for 3,000 shots. Sign up for the free ScreenshotNeo plan.

FAQ

Should CSS include the <style> tag?

Only when you are embedding it into an HTML string, as with dompdf. tc-lib-pdf’s global methods and mPDF’s stylesheet parser mode expect CSS text without surrounding style tags.

Can I use the same CSS string for every renderer?

You can share a baseline, but selectors and properties supported by one renderer may be ignored by another. Maintain renderer-specific adjustments and validate each output.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is a successful PDF generation call proof that the document is correct?

No. The call may succeed while pagination, fonts, images or unsupported CSS render incorrectly. Inspect representative PDFs and keep regression samples for upgrades.

Frequently Asked Questions

Should CSS include the

Recommended PC Tool
Recommended PC Tool

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.