← dompdf.js Studio

Text Wrapping and Word Breaking in dompdf.js

Text wrapping is the most overlooked and most damaging part of layout. Where Chinese breaks lines, whether English words may be split, whether long URLs overflow their containers, and how runs of digits behave — these details decide whether a PDF looks clean and professional or broken. In the browser, a bad wrap scrolls past and nobody notices, but a PDF is a deliverable: it gets printed, archived, and shared, and every wrapping flaw is permanently baked into the file. dompdf.js renders text through a real CSS layout engine, so the same rules the browser applies to word-break, overflow-wrap, and white-space apply to the PDF output, which means wrapping behavior verified in the browser survives the export. This guide walks through the mechanics behind that guarantee: how line breaking works at the algorithm level, why Chinese and Latin text break differently, what each wrapping property actually controls and when to use it, how to handle long URLs and unbroken strings, and the traps hidden in whitespace characters. Each section pairs explanation with real code you can drop into a template, and the closing section collects the failure modes most teams hit in production. By the end, wrapping should be a solved problem in your templates rather than a recurring bug report, and your exported PDFs should hold their layout across every content length and language mix. A useful mental model throughout: the engine already knows how to break lines correctly for the scripts you use; your job is only to tell it what to do with the strings that fall outside normal typography — and to keep your data from sabotaging its decisions with invisible characters.

How Line Breaking Works Under the Hood

Line breaking is decided by the layout engine based on character categories. Latin text breaks at spaces and hyphens, Chinese text may break between any two Han characters, and punctuation must not start a line. dompdf.js reuses browser-class line breaking rules, so text wraps in the PDF exactly as it wraps in the browser; unlike coordinate-based libraries that can push a whole paragraph onto one line and overflow the page, the engine handles wrapping natively. This is the concrete advantage of rendering real DOM, and it is why templates can be designed with confidence and verified in the browser before export.

The central concept is the line break opportunity: whether a given position may break depends on language and character class. English word interiors are not break opportunities, Chinese character boundaries are, and continuous unspaced strings like URLs are not. Every CSS wrapping property exists to adjust these opportunities — overflow-wrap adds them under overflow pressure, word-break changes the rules entirely, and white-space removes them. Understanding the model means every wrapping problem has a targeted fix instead of trial-and-error combinations.

It is also worth separating two ideas that get conflated: line breaking, which decides where lines normally end, and word breaking, which forcibly splits words. Chinese has no spaces and every Han character is a break opportunity, so Chinese documents almost never overflow; English depends on spaces and needs explicit strategies only for overly long words. The two cases need different tools, and applying one script's solution to the other produces the exact symptoms developers complain about.

One more distinction matters in practice: breaking inside a word for layout reasons is different from inserting a visible hyphen. Hyphenation engines and overflow breaking are separate mechanisms, and templates that rely on hyphens for visual balance should implement them explicitly rather than hoping the break properties will add them.

Chinese Line Breaking and Punctuation Rules

Chinese typesetting breaks lines between characters, so almost every position in a Chinese paragraph is a legal break point and overflow is rare. The real difficulty is punctuation: periods, commas, and closing quotes must not begin a line, opening quotes must not end one, and the standard has explicit kinsoku rules for these cases. dompdf.js follows these rules, so punctuation never dangles at the start of a line and the layout stays clean and conventional without any template effort.

Mixed Chinese-Latin runs break according to character class: boundaries between Han characters and Latin text are generally breakable, while runs of digits are not. The practical advice is to let the engine handle mixed copy automatically instead of inserting manual line breaks or spaces to fake alignment. Hand-aligned text breaks the moment the font size or face changes, and it breaks permanently, because the manual positions no longer match the new metrics; data-driven templates make this a recurring maintenance cost.

A more subtle Chinese concern is the mixing of Chinese and English quotation marks in the same paragraph, which reads as carelessness in a formal document. Standardizing punctuation style at the template level is more effective than patching behavior at the wrap level, and it also lets the engine's kinsoku handling work consistently, because the characters it sees are the ones the document standard actually specifies.

Vertical writing and punctuation width are edge cases that rarely affect horizontal documents, but if your audience includes traditional-Chinese readers, verify the built-in font covers the traditional characters your copy uses; coverage is not guaranteed by a simplified-Chinese font alone.

Kinsoku handling also covers the details most readers never notice: a closing bracket may not end a line, an opening bracket may not begin one, and consecutive punctuation is kept together. Because the engine applies these rules, a Chinese paragraph in dompdf.js breaks at conventional positions without configuration — but knowing the rules exist helps when a paragraph breaks at an unconventional position, because that is usually a signal that the content contains a character outside the expected script, such as a full-width space or a control character, rather than a layout failure.

Code Example: Controlling Wrapping with word-break and overflow-wrap

overflow-wrap: break-word permits breaks inside a word, but only when the word alone exceeds the container — the standard tool for long URLs, because it leaves normal text untouched and rescues only the overflow case. word-break: break-all breaks at any character unconditionally, which fits columns where every pixel of width matters, but it sacrifices English readability and, applied to Chinese, produces unnatural punctuation positions. Reserve break-all for constrained, data-heavy layouts and audit its effect on mixed copy.

keep-all is the inverse discipline: it forbids Chinese from breaking between characters and allows breaks only at spaces and explicit boundaries, useful when mixed copy has strict break-position requirements. anywhere behaves like break-word but creates more break opportunities, which makes it the practical choice for table cells holding long URLs: combined with a max-width on the cell, content wraps inside the column instead of inflating the table, and the row layout survives the longest string your data can produce.

These properties behave in dompdf.js exactly as in the browser, so verify wrapping in the browser with the same CSS before generating. One caveat: property names and values are case-sensitive and silently ignored when misspelled, returning the layout to defaults without any error. When a wrap looks wrong, first confirm the property actually applied — an inspect of the computed style in the browser settles it faster than any other debugging step.

A defensive pattern for untrusted data is to normalize the longest unbroken strings before they reach the template: inserting zero-width spaces at natural break points in URLs programmatically gives you controlled, elegant breaks instead of engine-chosen ones, at the cost of a small preprocessing step.

<style>
  .wrap-normal { word-break: normal; overflow-wrap: normal; }
  .wrap-break-word { overflow-wrap: break-word; }
  .wrap-break-all { word-break: break-all; }
  .wrap-keep-all { word-break: keep-all; }
  .url-cell { overflow-wrap: anywhere; }
  table td { max-width: 120px; }
</style>
<p class="wrap-normal">Normal paragraph with a long URL https://example.com/very/long/path/that/might/overflow</p>
<p class="wrap-break-word">Long URL https://example.com/very/long/path/that/might/overflow</p>
<p class="wrap-break-all">A very long word Pneumonoultramicroscopicsilicovolcanoconiosis in a narrow column</p>
<p class="wrap-keep-all">keep-all breaks Chinese at word boundaries and never splits English words</p>
<table><tr><td class="url-cell">https://example.com/very/long/path/in/table</td></tr></table>

Long URLs and Unbroken Character Runs

URLs, order numbers, and serial codes are the most common overflow sources: under default rules they cannot break internally, so a container that is too narrow overflows, and in a PDF that means text crossing borders or overlapping adjacent columns. Two remedies exist: allow internal breaks with overflow-wrap, or reformat the string at the template layer, such as giving long URLs their own line or reducing the font size for that element. Choose based on whether the content is user-generated or controlled by your system.

Allowing breaks has an aesthetic cost: break-word may split the string at any position, while breaks at slashes look natural. For documents where break positions are visible, preprocess URLs in JavaScript, inserting zero-width spaces after slashes and hyphens so the string becomes breakable at controlled points. The original text is preserved — zero-width spaces are invisible and do not affect copy-paste — while the visual breaks land where a reader expects them.

Tables are where unbroken strings do the most damage: a cell's width is driven by its content, so one long URL inflates an entire column and distorts the whole table. The reliable combination is a max-width or fixed width on the td, overflow-wrap: anywhere on the cell, and table-layout: fixed for full column control. Applied together, long strings wrap inside their cells, columns stay at their designed widths, and multi-column tables survive any data your system can throw at them.

For critical columns, consider a rendering strategy separate from layout: if a cell holds a URL that is both long and important, rendering the domain on one line and the path indented below it keeps the table compact and the URL readable, which is a layout decision best made in the template rather than left to the wrap engine.

Whitespace: nbsp, Newlines, and white-space

HTML collapses runs of spaces into one and treats newlines as spaces — a core rule of web layout that PDF rendering inherits. The trouble appears in data-driven templates: database text with stray newlines or full-width spaces produces unexpected break positions, and indentation that should survive gets merged away. The symptoms look like wrapping bugs, but the root cause is whitespace normalization, so the fix lives in how the content is prepared and styled rather than in wrap properties.

Preserve whitespace deliberately with the white-space property: pre keeps every space and newline, nowrap forbids wrapping, and pre-wrap keeps whitespace while still allowing automatic wraps. Code snippets, addresses, and poetry are the classic whitespace-sensitive content, and pre-wrap is the safest choice for them in documents: the original formatting survives and long content still wraps instead of overflowing the page. One property serves both fidelity and safety.

nbsp behaves completely differently from a normal space: no break is allowed on either side, which suits fixed combinations like year ranges and names that must stay on one line. The misuse is using nbsp for alignment — padding text with non-breaking spaces to line things up, which breaks instantly when the font or size changes. The correct tools are text-indent for indentation and tables or flex for alignment; reserve nbsp for its true semantic of an unbreakable space, and alignment problems stop recurring.

A related trap is the full-width space that creeps into CJK data entry. It is a different code point from the ASCII space and behaves differently in wrapping; normalize full-width spaces to regular spaces at the data boundary unless the content genuinely requires them, so wrap behavior is predictable for every input.

Common Problems and Best Practices

Q: The right edge of Chinese paragraphs looks ragged. A: Chinese breaks by character by default, so raggedness usually comes from mixed-script copy or punctuation squeezing. Check for an accidental word-break: break-all first; normal Chinese copy should use default breaking, optionally paired with text-align: justify to square off both margins.

Q: Long words blow out their container. A: Confirm overflow-wrap is set and the container has a max-width; in tables, table-layout: fixed is the third required piece. Most overflow reports trace back to one of these three missing, so adding all three closes the class of bugs rather than the individual case.

Q: A paragraph wraps in the browser but overflows in the PDF. A: The layout engine is the same, so the difference is usually context: a different container width, a different font, or a missed CSS rule in the template. Recreate the template's exact styles in the browser, and the discrepancy becomes reproducible and fixable.

Best-practice summary: default breaking for Chinese body copy; overflow-wrap: break-word for long URLs; anywhere plus fixed column widths in tables; pre-wrap for whitespace-sensitive content; no manual newlines and no nbsp alignment. Templates written to this standard stop generating wrapping bug reports, and delivered PDFs stay clean and professional across every content length and language the system supports.

Q: Wrapping is fine, but the PDF shows a stray empty line where my data had a newline. A: Newlines in the data are being treated as spaces or line breaks depending on white-space handling. If the content is a plain string from a database, normalize newlines before interpolation; if the content genuinely needs line breaks, wrap it in an element with white-space: pre-wrap so the breaks are intentional and the wrapping stays automatic.

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

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

Hello from dompdf.js!

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