← dompdf.js Studio

PDF Chinese Font Configuration Guide: dompdf.js Zero-Config Approach

Generating PDFs in Chinese is one of the most common and most painful tasks in frontend development. The symptoms are familiar to anyone who has tried: garbled characters, tofu blocks, or entire paragraphs that render as blank space. The traditional fixes are equally painful: install fonts on the server, bundle a 20 MB font file into the frontend assets, or convert text to images and permanently lose searchability and crispness. Libraries like jsPDF require you to register TTF font files manually before a single Chinese character will appear in the output, and every new project repeats that setup from scratch. dompdf.js takes a completely different path: it bundles Source Han Sans SC directly into the package, so Chinese text renders correctly out of the box. You instantiate a DomPDF object, pass it your HTML, and download a crisp, searchable, vector Chinese PDF — no font configuration whatsoever. Whether you are building invoices, contracts, reports, or resume exporters, understanding how Chinese fonts work in PDF generation will save you days of debugging. This guide covers why Chinese PDFs break, how dompdf.js solves the problem, complete code examples, styling details, and a practical troubleshooting checklist. By the end of this guide you will not only know how to produce correct Chinese PDFs, but also understand why other tools fail, which styling choices improve readability, and how to isolate encoding problems quickly. The examples are production-ready, so you can adapt them to invoices, contracts, or reports immediately, and the troubleshooting checklist doubles as a pre-release test plan for any template that contains Chinese text.

Why Chinese Text Breaks in PDFs

The root cause of garbled Chinese is almost always missing fonts. A PDF file does not carry the operating system's fonts with it. When the rendering engine tries to draw text and cannot find a usable Chinese font, it substitutes placeholder glyphs, which is why you see boxes, question marks, or entirely blank runs of text. The same HTML that looks perfect in Chrome can come out as garbage in a PDF because the PDF renderer has no access to the fonts the browser loaded for the page — the two environments live in completely different font worlds.

Teams typically reach for one of three workarounds, and each carries a hidden cost. The server-side approach installs Chinese font packages on the backend, which requires ops work and makes every render slower. The bundling approach ships font files to the browser and registers them manually, adding tens of megabytes to your assets and slowing down the initial page load. The image approach renders text to pictures, which kills text selection, search, and accessibility while making files dramatically larger and degrading print quality.

There is also a subtler problem that most workarounds ignore: even when the font is available, many popular tools output bitmap PDFs. The text is rasterized into pixels, so it blurs when zoomed and looks poor when printed. A professional result requires vector text — glyph outlines embedded in the PDF so the text stays sharp at any zoom level. That distinction matters far more than most tutorials acknowledge, because it determines whether the document can be searched, copied, and read by assistive technology at all.

Font problems rarely travel alone. Character encoding compounds the issue: if the database, the API, or the template layer is not UTF-8, the Chinese content is already corrupted before it ever reaches the rendering engine, and the PDF fails no matter which font is installed. When debugging garbled output, print the HTML string in the browser console first to confirm the content is intact, then inspect the render stage — this simple two-step isolation quickly narrows the problem to one layer instead of guessing across the whole stack.

A second, frequently overlooked cause is silent font fallback. When the renderer cannot find the exact font, it substitutes whatever face is available — often a Latin-only one — and the Chinese characters vanish from the output while the surrounding layout keeps its shape. That is why an export can look structurally correct and still be missing every Chinese character, a failure mode that is easy to mistake for a template bug and hard to spot in a quick visual scan.

Finally, do not underestimate the value of a minimal reproduction when things break. A tiny HTML file containing one heading and one paragraph of Chinese, exported through a clean DomPDF instance, tells you within minutes whether the problem lives in the library, the template, or the data pipeline. Keeping that test page in your repository makes future font or encoding regressions trivial to diagnose, and it doubles as the first entry in a shared team knowledge base.

The Zero-Config Solution: Bundled Source Han Sans SC

dompdf.js ships with Source Han Sans SC (思源黑体) built into the package. Source Han Sans is the open-source sans-serif family co-developed by Adobe and Google, and the SC variant covers the simplified Chinese character set used across mainland China. It includes the full GB2312 range plus a large number of less common characters, and it is free to use commercially, which removes a whole category of licensing worries for business applications.

Because the font is bundled and enabled by default, you do nothing to configure it. There is no @font-face rule to write, no addFont call, no separate font file to load, and no subsetting step to manage. You simply create a new DomPDF instance, call addPage with your Chinese HTML, and save the result. From first keystroke to a working Chinese PDF usually takes under a minute — which is the whole point of a zero-configuration design, and it means team members never need to learn font-specific knowledge.

The rendering core is written in Rust and compiled to WebAssembly. Glyphs are written into the PDF as vector paths rather than pixel data, which is why the output is small, searchable, selectable, and razor-sharp at any zoom or print resolution. This is the same quality bar that heavyweight server-side tools like headless Chrome achieve, but it happens entirely in the browser with none of the infrastructure — no servers, no font packages, no deployment steps to maintain.

Zero configuration pays off beyond the first export. Teams never need to synchronize font files or agree on font paths; every member pulls the code and generates Chinese PDFs immediately, and CI builds never fail because a font file is missing. For organizations that ship frequently and onboard developers often, removing font setup from the checklist eliminates a whole class of friction that other libraries quietly impose on every new environment.

One consequence of the bundled design is consistency across environments. Because the font ships inside the package rather than depending on the host machine, a PDF generated on a Windows laptop, a macOS workstation, or a Linux CI runner contains exactly the same glyphs. Developers who have debugged 'works on my machine' font issues will appreciate how quickly that entire class of problem disappears, and end users benefit from identical output regardless of the machine that produced it.

Code Example: Exporting a Chinese PDF

import { DomPDF } from 'dompdf.js';

const reportHTML = `
  <style>@page { margin: 20mm; }</style>
  <h1>月度销售报告</h1>
  <p>2026 年 8 月,华东大区销售额同比增长 23.6%,</p>
  <p>其中线上渠道贡献了 61.4% 的增量。</p>
  <table style="width:100%;border-collapse:collapse">
    <tr>
      <th style="border:1px solid #333;padding:8px">区域</th>
      <th style="border:1px solid #333;padding:8px">销售额</th>
    </tr>
    <tr>
      <td style="border:1px solid #333;padding:8px">华东</td>
      <td style="border:1px solid #333;padding:8px">¥ 1,286,500</td>
    </tr>
  </table>`;

// Chinese content goes directly into the HTML string,
// no font registration or configuration is required
const pdf = new DomPDF();
pdf.addPage(reportHTML, { format: 'A4', margin: '20mm' });
pdf.save('report.pdf');

Font Details: Size, Weight, and Styling

The bundled Chinese font supports both regular and bold weights out of the box. Setting font-weight: bold or wrapping text in a <b> tag produces bold glyphs without loading an additional bold font file, which keeps the package lean and the render fast. You never have to worry about weight mismatches producing faux-bold artifacts, and common needs like bold headings or emphasized amounts are one line of CSS away.

Font size is controlled with the standard font-size property, and both px and pt units are supported. For body text, 12-14px (roughly 9-10.5pt) works well for reading, with headings scaled up by hierarchy. Line-height between 1.5 and 1.8 makes Chinese paragraphs significantly more readable because CJK glyphs sit higher in the em box than Latin letters — the difference is immediately visible on long paragraphs of explanatory text.

If you want to mix fonts — for example, using a monospace face for numbers or English identifiers so table columns align — you can set font-family normally, and the bundled Source Han Sans SC remains available as a reliable fallback, so a missing font never collapses the whole page. When mixing CJK and Latin text, watch the inter-script spacing; a small letter-spacing adjustment often makes mixed lines look noticeably more polished and closer to the design mockup.

It is also worth planning the typography of the whole document rather than individual elements: consistent heading scale, consistent paragraph spacing, and consistent table cell padding make a Chinese PDF look professionally designed even when the content is generated dynamically. Because dompdf.js renders real CSS, the same design tokens you use on the web page carry over to the PDF, so your brand language stays uniform across screen and print.

One more styling note for mixed-language documents: keep Latin text in its own spans when precise alignment matters. Numbers and English identifiers inside Chinese paragraphs often look better in a proportional Latin face, and giving them an explicit span makes the intent visible in the template. Small touches like this are what separate a functional export from a polished one, and they cost nothing at render time.

Troubleshooting Common Font Problems

Q: The exported PDF shows boxes instead of Chinese characters? A: First check your dompdf.js version. Early releases did not bundle a CJK font; upgrade to the latest version, clear the build cache, and rebuild. If the problem persists, confirm that your HTML is actually UTF-8 encoded end to end — inconsistent charsets cause rendering failures even with a correct font.

Q: Rare or obscure characters do not render? A: Source Han Sans covers tens of thousands of glyphs, so the vast majority of uncommon characters render fine. A few characters in extension planes may be missing; for those, substitute a common synonym or rephrase the text rather than leaving holes in the document.

Q: How do I use a custom font? A: The most reliable approach today is to stick with the bundled font and control appearance through CSS. If your business genuinely requires a special typeface, check the official documentation for the font-extension interface and follow its API rather than hacking around it, so you do not introduce instability.

Q: Why does the Chinese in the PDF look smaller than on the web page? A: This is almost always a px-versus-pt confusion. Remember that 1pt is approximately 1.333px. Use one unit consistently across your CSS and the on-screen preview will match the PDF output, which also makes design reviews much smoother.

Q: Some templates work and others produce garbage intermittently? A: This is usually a data-source encoding mismatch — for example, records imported from a legacy system that stored text in GBK. Normalize the encoding once at the data entry point, convert everything to UTF-8 before it enters the template, and the problem disappears for good rather than reappearing randomly.

One general debugging habit helps across all of these symptoms: keep a single, known-good HTML sample that you can export at any time. When a new report misbehaves, export the sample first — if the sample is clean, the problem is in your template or data; if the sample is also broken, the problem is environmental. This two-minute check has saved more debugging hours than any other technique in this guide, and it costs one small file in the repository.

How Other Libraries Handle Chinese Fonts

jsPDF ships with standard Latin fonts such as Helvetica, none of which contain Chinese glyphs. To render Chinese you must call addFileToVFS and addFont to register a TTF file, then deal with font subsetting and file size yourself. It works, but it is fiddly configuration work that every project repeats from scratch, and newcomers get stuck on it constantly.

html2pdf.js takes a screenshot of the page via html2canvas and embeds that bitmap into the PDF. Chinese text therefore depends entirely on whether the page's own fonts finished loading — if the font is not ready when the screenshot is taken, you get blank or misaligned text. And because the output is a bitmap, the text cannot be selected or searched and blurs when zoomed, which is a weak experience for Chinese documents.

Server-side solutions like Puppeteer produce excellent results but require installing CJK font packages on the server and running a headless browser, which is heavy infrastructure for a routine export. Against all of these, dompdf.js's approach — bundling the font and rendering vector text in the browser — is the lowest-configuration, highest-quality option for Chinese PDF generation on the frontend, and it deserves a serious evaluation in any new project.

One more angle worth mentioning: maintenance. jsPDF's font configuration lives in application code and must be repeated or wrapped for every project; html2pdf.js depends on the page loading fonts in time; server solutions depend on ops installing packages. dompdf.js moves the entire font problem into the library itself, so the knowledge lives in the dependency instead of in your codebase — fewer moving parts to own.

One practical note for teams evaluating options: measure the total cost of ownership, not just the first export. jsPDF's Chinese setup has to be re-derived for every project and every font variant; html2pdf.js output quality depends on the end user's browser and fonts; server solutions require provisioning and monitoring. dompdf.js moves all of that into the dependency itself, which is why the long-term cost is lower even when the short-term demo looks similar.

⚡ 现场演示(点击生成 PDF)

下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:

Hello from dompdf.js!

这是由 dompdf.js 渲染的示例 PDF 内容。